Snap for 6439596 from d34906b95367a971c79c2da4401faad1b9961cca to qt-aml-tzdata-release
Change-Id: If76f5fdf6d1184967b7e12800769090bb47fa826
diff --git a/.bazelrc b/.bazelrc
deleted file mode 100644
index ecd54a5..0000000
--- a/.bazelrc
+++ /dev/null
@@ -1,8 +0,0 @@
-# Include debug info in the compiled jars
-build --javacopt=-g
-build --host_javacopt=-g
-
-# Disable The Guava Beta Checker.
-# TODO(ronshapiro): explore how much work it would be to reenable this
-build --javacopt="-Xep:BetaApi:OFF"
-build --host_javacopt="-Xep:BetaApi:OFF"
diff --git a/.gitignore b/.gitignore
index fabb38f..0c4de1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,4 @@
-*~
-\#*\#
-
-.classpath
-.factorypath
-.project
-.settings
-eclipsebin
-
-bin
-gen
-build
-out
-#lib
-
-target
-pom.xml.*
-release.properties
-build.log
-
-.idea
*.iml
-classes
-
-obj
-
-.DS_Store
-
-dependency-reduced-pom.xml
-
-gen-external-apklibs
-
-/bazel-*
-
-*.pyc
+*.ipr
+*.iws
+.idea
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 9015f2e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-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/AUTHORS b/AUTHORS
deleted file mode 100644
index f4a0fdd..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-# This is the list of Dagger authors for copyright purposes.
-#
-# This does not necessarily list everyone who has contributed code, since in
-# some cases, their employer may be the copyright holder. To see the full list
-# of contributors, see the revision history in source control.
-Google Inc.
-Square Inc.
-and other contributors
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 27a05c5..f8e59ef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,12 +14,12 @@
java_import_host {
name: "dagger2-auto-common",
- jars: ["lib/auto-common-0.10.jar"],
+ jars: ["lib/auto-common-1.0-20151022.071545-39.jar"],
}
java_import_host {
name: "dagger2-auto-factory-jar",
- jars: ["lib/auto-factory-1.0-beta6.jar"],
+ jars: ["lib/auto-factory-1.0-20150915.183854-35.jar"],
}
java_plugin {
@@ -29,19 +29,12 @@
"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"],
+ jars: ["lib/auto-service-1.0-rc2.jar"],
}
java_plugin {
@@ -50,28 +43,19 @@
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"],
+ jars: ["lib/auto-value-1.4.1.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",
- ],
+ static_libs: ["dagger2-auto-value-jar"],
}
java_plugin {
@@ -82,64 +66,42 @@
java_import_host {
name: "dagger2-google-java-format",
- jars: ["lib/google-java-format-1.7-all-deps.jar"],
+ jars: ["lib/google-java-format-0.1-20151017.042846-2.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_compiler_deploy.jar"],
-}
-
-java_plugin {
- name: "dagger2-bootstrap-compiler",
- processor_class: "dagger.internal.codegen.ComponentProcessor",
- generates_api: true,
- static_libs: ["dagger2-bootstrap-compiler-jar"],
+ jars: ["lib/javax-inject.jar"],
}
java_library_host {
name: "dagger2",
- srcs: [
- "java/dagger/*.java",
- "java/dagger/internal/*.java",
- "java/dagger/multibindings/*.java",
- "java/dagger/releasablereferences/*.java",
- ],
- exclude_srcs: ["java/dagger/android/**/*.java"],
+ srcs: ["core/src/main/java/**/*.java"],
static_libs: ["dagger2-inject"],
libs: ["guava"],
- java_version: "1.8",
+ java_version: "1.7",
}
-// build dagger2 producers library
+// build dagger2 producers plugin
// ============================================================
-java_library_host {
+java_plugin {
name: "dagger2-producers",
- srcs: ["java/dagger/producers/**/*.java"],
+ srcs: ["producers/src/main/java/**/*.java"],
- static_libs: [
- "dagger2-inject",
- "error_prone_annotations",
- ],
+ static_libs: ["dagger2-inject"],
libs: [
"dagger2",
- "dagger2-android-annotation-stubs",
"guava",
],
- java_version: "1.8",
+ java_version: "1.7",
}
// build dagger2 compiler plugin
@@ -149,20 +111,10 @@
name: "dagger2-compiler",
processor_class: "dagger.internal.codegen.ComponentProcessor",
generates_api: true,
- use_tools_jar: true,
- srcs: [
- "java/dagger/internal/codegen/**/*.java",
- "java/dagger/internal/codegen/**/*.proto",
-
- "java/dagger/model/*.java",
- "java/dagger/spi/*.java",
- ],
-
- exclude_srcs: [
- "java/dagger/internal/codegen/BindingGraphStatisticsCollector.java",
- "java/dagger/internal/codegen/DaggerKythePlugin.java",
- ],
+ // Required for use of javax.annotation.Generated per http://b/62050818
+ javacflags: ["-J--add-modules=java.xml.ws.annotation"],
+ srcs: ["compiler/src/main/java/**/*.java"],
// Manually include META-INF/services/javax.annotation.processing.Processor
// as the AutoService processor doesn't work properly.
@@ -178,14 +130,6 @@
"dagger2-inject",
"dagger2-producers",
"guava",
- "javapoet",
- ],
-
- // shade guava to avoid conflicts with guava embedded in Error Prone.
- jarjar_rules: "jarjar-rules.txt",
-
- libs: [
- "dagger2-android-annotation-stubs",
],
plugins: [
@@ -193,22 +137,7 @@
"dagger2-auto-service",
"dagger2-auto-value",
"dagger2-auto-annotation",
- "dagger2-bootstrap-compiler",
],
- proto: {
- type: "full",
- include_dirs: ["external/protobuf/src/"],
- },
-
- java_version: "1.8",
-}
-
-// Compile dummy implementations of annotations used by dagger2 but not
-// present in the Android tree.
-java_library {
- name: "dagger2-android-annotation-stubs",
- host_supported: true,
- sdk_version: "core_current",
- srcs: ["android-annotation-stubs/src/**/*.java"],
+ java_version: "1.7",
}
diff --git a/BUILD b/BUILD
deleted file mode 100644
index 8becb3e..0000000
--- a/BUILD
+++ /dev/null
@@ -1,179 +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(default_visibility = ["//visibility:public"])
-
-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"],
- exports = ["//java/dagger:core"],
-)
-
-java_library(
- name = "producers_with_compiler",
- exports = [
- ":dagger_with_compiler",
- "//java/dagger/producers",
- ],
-)
-
-android_library(
- name = "android",
- exported_plugins = ["//java/dagger/android/processor:plugin"],
- exports = ["//java/dagger/android"],
-)
-
-android_library(
- name = "android-support",
- exports = [
- ":android",
- "//java/dagger/android/support",
- ],
-)
-
-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",
- "@com_google_auto_auto_common//jar",
- ],
- rules = SHADE_RULES,
-)
-
-jarjar_library(
- name = "shaded_grpc_server_processor",
- jars = [
- "//java/dagger/grpc/server/processor",
- "@com_google_auto_auto_common//jar",
- ],
- rules = SHADE_RULES,
-)
-
-# coalesced javadocs used for the gh-pages site
-javadoc_library(
- name = "user-docs",
- 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/model:model-srcs",
- "//java/dagger/producers:producers-srcs",
- "//java/dagger/spi:spi-srcs",
- ],
- 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.internal",
- "dagger.producers.internal",
- "dagger.producers.monitoring.internal",
- ],
- root_packages = ["dagger"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/android",
- "//java/dagger/android/support",
- "//java/dagger/grpc/server",
- "//java/dagger/grpc/server/processor",
- "//java/dagger/model",
- "//java/dagger/producers",
- "//java/dagger/spi",
- ],
-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09c4282..3a38bfc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,87 @@
Change Log
==========
-- For Dagger 2 releases, please see https://github.com/google/dagger/releases
-- For Dagger 1 (`ObjectGraph`) releases, see
- https://github.com/square/dagger/blob/master/CHANGELOG.md
+Dagger 2 (Components)
+---------------------
+
+### Version 2.0.2 *(2015-11-03)*
+
+A patch release, most crucially including:
+
+ * A fix to the way processor validation of types is done that permits dagger to play
+ more nicely with other processors, avoiding over-validating aspects that it doesn't
+ need, which may yet not have been generated by other processors in a different round
+ of processing.
+ * Some improved error reporting for edge-cases
+ * Fix to prevent incompatible versions of Guava on the classpath from blowing up processing
+ * Support a more robust set of types for map keys in map bindings (primitive types, etc.)
+
+### Version 2.0.1 *(2015-05-28)*
+
+A maintenance release fixing immediate issues following the Dagger 2.0 release, including:
+
+ * Speed up Graph Validation (reduce build times by 10s of seconds on sampled large projects)
+ * Generate correct code for @MapKey annotation types (beta)
+ * Fix to properly emit code for class literal values in @MapKey annotations.
+ * Fix for injecting component dependencies
+ * Fixes to generated code to account for differences in generics handling in ecg vs. javac.
+ * Subcomponents can now be abstract classes.
+ * Subcomponents now properly build the object graph in some cases involving explicit bindings
+ and (sub)components without scope.
+ * Improve runtime performance of SetFactory (set multibindings)
+ * Other smaller fixes, refactorings, etc.
+
+### Version 2.0.0 *(2015-04-21)*
+
+The initial release of the 2.0 code-line, supporting:
+
+ * `@Component` interfaces representing a custom API to access a graph of objects
+ * JSR-330 injection automation using `@Inject` signals, `@Qualifiers`
+ * Simple bindings of implementations to interfaces, custom provision of objects, and set-bindings
+ * Compile-time validation of graph structure (cycles, missing bindings, duplicate bindings)
+ * Generation of
+ - backing implementations for components
+ - factories for `@Inject` constructors and modules
+ - members-injectors for `@Inject` methods and fields
+ * Beta support for
+ - Map bindings
+ - [Producers](http://google.github.io/dagger/api/latest/dagger/producers/Producer.html)
+
+==============================================================
+
+Dagger 1 (ObjectGraph)
+----------------------
+
+### Version 1.2.0 *(2013-12-13)*
+
+ * Numerous performance improvements in both the compiler and runtime.
+ * Use more efficient `String` concatenation.
+ * Module adapters are now stateless.
+ * Use read/write locks over global locks.
+ * Reflective constructor invocation is now cached with `Class.newInstance`.
+ * Avoid re-linking all bindings when calling `.plus()`.
+ * Set bindings are now unioned when calling `.plus()`.
+ * Fix: Tolerate missing type information during compilation by deferring writing
+ module adapters.
+
+
+### Version 1.1.0 *(2013-08-05)*
+
+ * Module loading now requires code generation via the 'dagger-compiler' artifact.
+ * Allow multiple contributions to Set binding via `Provides.Type.SET_VALUES`.
+ * Request classloading from the classloader of the requesting object, not the current thread's
+ context classloader.
+ * Cache class loading at the root injector to reduce costs of loading adapters.
+ * Fix: Primitive array types are no longer incorrectly changed to their boxed type.
+ * Update JavaWriter to 2.1.1.
+
+
+### Version 1.0.1 *(2013-06-03)*
+
+ * Explicitly forbid declaring `@Inject` on a class type (e.g., `@Inject class Foo {}`).
+ * Update JavaWriter to 1.0.5.
+
+
+### Version 1.0.0 *(2013-05-07)*
+
+Initial release.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 45f15c4..087af22 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,69 +1,37 @@
-# How to contribute
+Contributing
+============
-We'd love to accept your patches and contributions to this project. There are
-just a few small guidelines you need to follow.
+If you would like to contribute code to Dagger you can do so through GitHub by
+forking the repository and sending a pull request.
-## Contributor License Agreement
+When submitting code, please make every effort to follow existing conventions
+and style in order to keep the code as readable as possible.
-Contributions to any Google project must be accompanied by a Contributor License
-Agreement. This is necessary because you own the copyright to your changes, even
-after your contribution becomes part of this project. So this agreement simply
-gives us permission to use and redistribute your contributions as part of the
-project. Head over to <https://cla.developers.google.com/> to see your current
-agreements on file or to sign a new one.
+Where appropriate, please provide unit tests or integration tests. Unit tests
+should be JUnit based tests and can use either standard JUnit assertions or
+FEST assertions and be added to `<project>/src/test/java`. Changes to build-time
+behaviour (such as changes to code generation or graph validation) should go into
+small maven projects using the `maven-invoker-plugin`. Examples of this are in
+`core/src/it` and can include bean-shell verification scripts and other
+facilities provided by `maven-invoker-plugin`.
-You generally only need to submit a CLA once, so if you've already submitted one
-(even if it was for a different project), you probably don't need to do it
-again.
+Please make sure your code compiles by running `mvn clean verify` which will
+execute both unit and integration test phases. Additionally, consider using
+http://travis-ci.org to validate your branches before you even put them into
+pull requests. All pull requests will be validated by Travis-ci in any case
+and must pass before being merged.
-## Code reviews
+If you are adding or modifying files you may add your own copyright line, but
+please ensure that the form is consistent with the existing files, and please
+note that a Square, Inc. copyright line must appear in every copyright notice.
+All files are released with the Apache 2.0 license.
-All submissions, including submissions by project members, require review. We
-use GitHub pull requests for this purpose. Consult [GitHub Help] for more
-information on using pull requests.
+Checkstyle failures during compilation indicate errors in your style and will
+be displayed in the console output of the build (including in Travis-CI output),
+or can be viewed in the `checkstyle-result.xml` file.
-[GitHub Help]: https://help.github.com/articles/about-pull-requests/
+Before your code can be accepted into the project you must sign the
+[Individual Contributor License Agreement (CLA)][1].
-## Building Dagger
-Dagger is built with [`bazel`](https://bazel.build).
-
-### Building Dagger from the command line
-
-* [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].
- * 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
-* 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`
- version.
-
-[bazel targets]: https://docs.bazel.build/versions/master/build-ref.html
-
-### Importing the Dagger project in IntelliJ/Android Studio
-
-* Visit `Preferences > Plugins` in the IDE menu.
- * Search for `bazel` and install the plugin.
- * If no result shows up, click on `Search in repositories`, search for
- `bazel` and install the plugin.
-* Select `Import Bazel Project`.
-* Input the path to the Dagger project under `workspace`, click `Next`.
-* Select `Generate from BUILD file`, type `BUILD` in the `Build file` input,
- click `Next`.
-* [Android Studio only] In the `Project View` form, uncomment one of the
- `android_sdk_platform` lines. Pick one that you have installed, then click
- `Finish`.
-* If you get an error on Bazel sync, `Cannot run program "bazel"`, then:
- * In the command line, run `where bazel` and copy the output (e.g.
- `/usr/local/bin/bazel`)
- * In Android Studio, go to `Preferences > Bazel Settings` and replace
- `Bazel binary location` with what you just copied.
-* Note that the first sync can take a long time. When build files are changed,
- you can run partial syncs (which should be faster) from the file menu.
-* [Android Studio only] To view the Dagger project structure, open the
- `Project` view and switch the top selector from `Android` to `Project`.
+ [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
diff --git a/METADATA b/METADATA
deleted file mode 100644
index 59b9e25..0000000
--- a/METADATA
+++ /dev/null
@@ -1,17 +0,0 @@
-name: "dagger2"
-description:
- "A fast dependency injector for Android and Java."
-
-third_party {
- url {
- type: HOMEPAGE
- value: "https://dagger.dev"
- }
- url {
- type: GIT
- value: "https://github.com/google/dagger"
- }
- version: "dagger-2.23.1"
- last_upgrade_date { year: 2019 month: 6 day: 14 }
- license_type: PERMISSIVE
-}
diff --git a/OWNERS b/OWNERS
index 87a5dbe..22cc91a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1,2 @@
-include platform/libcore:/OWNERS
+paulduffin@google.com
+nfuller@google.com
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..1983221
--- /dev/null
+++ b/README.android
@@ -0,0 +1,12 @@
+URL: https://github.com/google/dagger.git
+License: Apache 2
+Description: "Dagger 2 - A fast dependency injector for Android and Java"
+
+Version: 91f7d8bda5b1ef2fdf768758c88d3e5f069210ea
+
+Upstream depends (slightly) on Guava v19 but we only have Guava v18 in
+Android at the moment so we have reverted those changes that introduced
+a dependency on Guava v19.
+
+Local Patches:
+ Revert "Stop using deprecated Futures method." - upstream 0a2ca81c0f78c621968deb58f4b42117db43fec4
diff --git a/README.md b/README.md
index a9ebc26..3c0e8bc 100644
--- a/README.md
+++ b/README.md
@@ -1,204 +1,110 @@
-# Dagger 2
-
-[![Maven Central][mavenbadge-svg]][mavencentral]
+Dagger 2
+========
A fast dependency injector for Android and Java.
-## About Google's Fork
+About Google's Fork
+-------------
-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.
+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.0 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.
+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 benefitted 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]
-> [Dagger 2's main documentation website can be found here.][website]
+Status
+------
-## Documentation
+ - ***Release Version:* 2.0.1**
+ - ***Snapshot Version:* 2.1-SNAPSHOT**
+
+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 a clean build with the version `2.1-SNAPSHOT`.
+
+Documentation
+-------------
You can [find the dagger documentation here][website] which has extended usage
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],
+You can also learn more from [the original proposal][proposal],
[this talk by Greg Kick][gaktalk], and on the dagger-discuss@googlegroups.com
-mailing list.
+mailing list.
-## Installation
+Installation
+--------
-### Bazel
-
-If you build with `bazel`, follow the [`bazel` documentation for referencing
-external projects][bazel-external-deps] to include Dagger in your build.
-
-Given the following `WORKSPACE` definition, you can reference dagger via
-`@com_google_dagger//:dagger_with_compiler` in your deps.
-
-```python
-http_archive(
- name = "com_google_dagger",
- urls = ["https://github.com/google/dagger/archive/dagger-<version>.zip"],
-)
-```
-
-### Other build systems
-
-You will need to include the `dagger-2.x.jar` in your application's runtime.
+You will need to include the `dagger-2.0.1.jar` in your application's runtime.
In order to activate code generation and generate implementations to manage
-your graph you will need to include `dagger-compiler-2.x.jar` in your build
+your graph you will need to include `dagger-compiler-2.0.1.jar` in your build
at compile time.
-#### Maven
-
In a Maven project, include the `dagger` artifact in the dependencies section
-of your `pom.xml` and the `dagger-compiler` artifact as an
-`annotationProcessorPaths` value of the `maven-compiler-plugin`:
+of your `pom.xml` and the `dagger-compiler` artifact as either an `optional` or
+`provided` dependency:
```xml
<dependencies>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
- <version>2.x</version>
- </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>2.x</version>
- </path>
- </annotationProcessorPaths>
- </configuration>
- </plugin>
- </plugins>
-</build>
-```
-
-If you are using a version of the `maven-compiler-plugin` lower than `3.5`, add
-the `dagger-compiler` artifact with the `provided` scope:
-
-```xml
-<dependencies>
- <dependency>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger</artifactId>
- <version>2.x</version>
+ <version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
- <version>2.x</version>
- <scope>provided</scope>
+ <version>2.0.1</version>
+ <optional>true</optional>
</dependency>
</dependencies>
```
-If you use the beta `dagger-producers` extension (which supplies
-parallelizable execution graphs), then add this to your maven configuration:
+If you use the beta `dagger-producers` extension (which supplies parallelizable execution graphs),
+then add this to your maven configuration:
```xml
<dependencies>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-producers</artifactId>
- <version>2.x</version>
+ <version>2.0-beta</version>
</dependency>
</dependencies>
```
-#### 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 {
- compile 'com.google.dagger:dagger:2.x'
- annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
-}
-```
-
-If you're using classes in `dagger.android` you'll also want to include:
-
-```groovy
-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'
-```
-
-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
-error, databinding compilation will halt and sometimes print more than 100
-errors, which is the default amount for `javac`. For more information, see
-[Issue 306](https://github.com/google/dagger/issues/306).
-
-```groovy
-gradle.projectsEvaluated {
- tasks.withType(JavaCompile) {
- options.compilerArgs << "-Xmaxerrs" << "500" // or whatever number you want
- }
-}
-```
-
-### Download
+### Download
* 2.x (google/dagger)
* [Dagger 2.0 Documentation][website]
* [Dagger 2.0 Javadocs][20api]
- * [Dagger development Javadocs][latestapi] (from the `master` branch
- on GitHub)
+ * [Dagger development Javadocs][latestapi] (from the `master` branch on GitHub)
* [Google's Dagger project site on GitHub][project]
+ * <a href="https://plus.google.com/118328287768685565185" rel="publisher">Google+ Dagger Project Page</a>
+ * [Google+ Dagger Users Community][community]
* 1.x (square/dagger)
* [Square's original Dagger project site on GitHub][square]
+ * [Square Open Source Community][squarecommunity]
-If you do not use maven, gradle, ivy, or other build systems that consume
-maven-style binary artifacts, they can be downloaded directly via the
-[Maven Central Repository][mavencentral].
+If you do not use maven, gradle, ivy, or other build systems that consume maven-style binary
+artifacts, they can be downloaded directly via the [Maven Central Repository][mavensearch].
-Developer snapshots are available from Sonatype's
-[snapshot repository][dagger-snap], and are built on a clean build of
-the GitHub project's master branch.
+Developer snapshots are available from [Sonatype's snapshot repository][dagger-snap], and
+are built on a clean build of the GitHub project's master branch.
-## Building Dagger
+License
+-------
-See [the CONTRIBUTING.md docs][Building Dagger].
-
-## License
-
- Copyright 2012 The Dagger Authors
+ Copyright 2012 Square, Inc.
+ Copyright 2012 Google, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -212,17 +118,17 @@
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
-[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
-[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
-[project]: http://github.com/google/dagger/
-[proposal]: https://github.com/square/dagger/issues/366
-[square]: http://github.com/square/dagger/
-[website]: https://dagger.dev
+
+
+ [mavensearch]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.google.dagger%22
+ [dagger-snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/dagger/
+ [website]: http://google.github.io/dagger
+ [latestapi]: http://google.github.io/dagger/api/latest/
+ [20api]: http://google.github.io/dagger/api/2.0/
+ [gaktalk]: https://www.youtube.com/watch?v=oK_XtfXPkqw
+ [proposal]: https://github.com/square/dagger/issues/366
+ [project]: http://github.com/google/dagger/
+ [community]: https://plus.google.com/communities/111933036769103367883
+ [square]: http://github.com/square/dagger/
+ [squarecommunity]: https://plus.google.com/communities/109244258569782858265
+
diff --git a/WORKSPACE b/WORKSPACE
deleted file mode 100644
index 8758b38..0000000
--- a/WORKSPACE
+++ /dev/null
@@ -1,34 +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.
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-http_archive(
- name = "google_bazel_common",
- 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()
-
-# 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
-bind(
- name = "zlib",
- actual = "@bazel_tools//third_party/zlib",
-)
diff --git a/android-annotation-stubs/gen_annotations.sh b/android-annotation-stubs/gen_annotations.sh
deleted file mode 100755
index 21aeb46..0000000
--- a/android-annotation-stubs/gen_annotations.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash
-
-declare -A INNER
-declare -A PARAMETER
-declare -A IMPORT
-
-ANNOTATIONS=(
- org.checkerframework.checker.nullness.compatqual.NullableDecl
- net.ltgt.gradle.incap.IncrementalAnnotationProcessor
-)
-
-PARAMETER["net.ltgt.gradle.incap.IncrementalAnnotationProcessor"]="IncrementalAnnotationProcessorType"
-IMPORT["net.ltgt.gradle.incap.IncrementalAnnotationProcessor"]="net.ltgt.gradle.incap.IncrementalAnnotationProcessorType"
-
-for a in ${ANNOTATIONS[@]}; do
- package=${a%.*}
- class=${a##*.}
- dir=$(dirname $0)/src/${package//.//}
- file=${class}.java
- inner=${INNER[$a]}
- parameter=${PARAMETER[$a]}
- import=
-
- if [ -n "${parameter}" ]; then
- parameter="${parameter} value();"
- fi
-
- for i in ${IMPORT[$a]}; do
- import="${import}import ${i};"
- done
-
- mkdir -p ${dir}
- sed -e"s/__PACKAGE__/${package}/" \
- -e"s/__CLASS__/${class}/" \
- -e"s/__INNER__/${inner}/" \
- -e"s/__PARAMETER__/${parameter}/" \
- -e"s/__IMPORT__/${import}/" \
- $(dirname $0)/tmpl.java > ${dir}/${file}
- google-java-format -i ${dir}/${file}
-done
-
-f=$(dirname $0)/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
-cat > ${f} <<EOF
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.ltgt.gradle.incap;
-public enum IncrementalAnnotationProcessorType {
- DYNAMIC
-}
-EOF
diff --git a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessor.java b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessor.java
deleted file mode 100644
index aa1ce76..0000000
--- a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessor.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.ltgt.gradle.incap;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/* This is an annotation stub to avoid dependencies on annotations that aren't
- * in the Android platform source tree. */
-
-@Target({
- ElementType.ANNOTATION_TYPE,
- ElementType.CONSTRUCTOR,
- ElementType.FIELD,
- ElementType.LOCAL_VARIABLE,
- ElementType.METHOD,
- ElementType.PACKAGE,
- ElementType.PARAMETER,
- ElementType.TYPE,
- ElementType.TYPE_PARAMETER,
- ElementType.TYPE_USE
-})
-@Retention(RetentionPolicy.SOURCE)
-public @interface IncrementalAnnotationProcessor {
-
- IncrementalAnnotationProcessorType value();
-}
diff --git a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
deleted file mode 100644
index 83e3590..0000000
--- a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.ltgt.gradle.incap;
-public enum IncrementalAnnotationProcessorType {
- DYNAMIC
-}
diff --git a/android-annotation-stubs/src/org/checkerframework/checker/nullness/compatqual/NullableDecl.java b/android-annotation-stubs/src/org/checkerframework/checker/nullness/compatqual/NullableDecl.java
deleted file mode 100644
index 2d39b0f..0000000
--- a/android-annotation-stubs/src/org/checkerframework/checker/nullness/compatqual/NullableDecl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.checkerframework.checker.nullness.compatqual;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/* This is an annotation stub to avoid dependencies on annotations that aren't
- * in the Android platform source tree. */
-
-@Target({
- ElementType.ANNOTATION_TYPE,
- ElementType.CONSTRUCTOR,
- ElementType.FIELD,
- ElementType.LOCAL_VARIABLE,
- ElementType.METHOD,
- ElementType.PACKAGE,
- ElementType.PARAMETER,
- ElementType.TYPE,
- ElementType.TYPE_PARAMETER,
- ElementType.TYPE_USE
-})
-@Retention(RetentionPolicy.SOURCE)
-public @interface NullableDecl {}
diff --git a/android-annotation-stubs/tmpl.java b/android-annotation-stubs/tmpl.java
deleted file mode 100644
index c4df609..0000000
--- a/android-annotation-stubs/tmpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package __PACKAGE__;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-__IMPORT__
-
-/* This is an annotation stub to avoid dependencies on annotations that aren't
- * in the Android platform source tree. */
-
-@Target({
- ElementType.ANNOTATION_TYPE,
- ElementType.CONSTRUCTOR,
- ElementType.FIELD,
- ElementType.LOCAL_VARIABLE,
- ElementType.METHOD,
- ElementType.PACKAGE,
- ElementType.PARAMETER,
- ElementType.TYPE,
- ElementType.TYPE_PARAMETER,
- ElementType.TYPE_USE})
-@Retention(RetentionPolicy.SOURCE)
-public @interface __CLASS__ {
- __INNER__
- __PARAMETER__
-}
diff --git a/build_defs.bzl b/build_defs.bzl
deleted file mode 100644
index 0bd7402..0000000
--- a/build_defs.bzl
+++ /dev/null
@@ -1,26 +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 file defines constants useful across the Dagger build."""
-
-DOCLINT_HTML_AND_SYNTAX = ["-Xdoclint:html,syntax"]
-
-DOCLINT_REFERENCES = ["-Xdoclint:reference"]
-
-SOURCE_7_TARGET_7 = [
- "-source",
- "1.7",
- "-target",
- "1.7",
-]
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 0000000..e7ffbc0
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+
+<module name="Checker">
+ <!--module name="NewlineAtEndOfFile"/-->
+ <module name="FileLength"/>
+ <module name="FileTabCharacter"/>
+
+ <!-- Trailing spaces -->
+ <module name="RegexpSingleline">
+ <property name="format" value="\s+$"/>
+ <property name="message" value="Line has trailing spaces."/>
+ </module>
+
+ <!-- Space after 'for' and 'if' -->
+ <module name="RegexpSingleline">
+ <property name="format" value="^\s*(for|if)[^ ]"/>
+ <property name="message" value="Space needed before opening parenthesis."/>
+ </module>
+
+ <!-- For each spacing -->
+ <module name="RegexpSingleline">
+ <property name="format" value="^\s*for \(.*?([^ ]:|:[^ ])"/>
+ <property name="message" value="Space needed around ':' character."/>
+ </module>
+
+ <module name="TreeWalker">
+ <property name="cacheFile" value="${checkstyle.cache.file}"/>
+
+ <!-- Checks for Javadoc comments. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <!--module name="JavadocMethod"/-->
+ <!--module name="JavadocType"/-->
+ <!--module name="JavadocVariable"/-->
+ <!--module name="JavadocStyle"/-->
+
+
+ <!-- Checks for Naming Conventions. -->
+ <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <!--<module name="ConstantName"/>-->
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+
+
+ <!-- Checks for imports -->
+ <!-- See http://checkstyle.sf.net/config_import.html -->
+ <module name="AvoidStarImport"/>
+ <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
+ <module name="RedundantImport"/>
+ <module name="UnusedImports">
+ <property name="processJavadoc" value="true"/>
+ </module>
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <module name="LineLength">
+ <property name="max" value="100"/>
+ </module>
+ <module name="MethodLength">
+ <property name="max" value="200"/>
+ </module>
+ <!--module name="ParameterNumber"/-->
+
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="GenericWhitespace"/>
+ <module name="EmptyForIteratorPad"/>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceAfter"/>
+ <module name="NoWhitespaceBefore"/>
+ <module name="OperatorWrap"/>
+ <module name="ParenPad"/>
+ <module name="TypecastParenPad"/>
+ <module name="WhitespaceAfter"/>
+ <module name="WhitespaceAround">
+ <property name="allowEmptyConstructors" value="true" />
+ <property name="allowEmptyMethods" value="true" />
+ </module>
+
+
+ <!-- Modifier Checks -->
+ <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <!--module name="ModifierOrder"/-->
+ <module name="RedundantModifier"/>
+
+
+ <!-- Checks for blocks. You know, those {}'s -->
+ <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <!--module name="AvoidNestedBlocks"/-->
+ <!--module name="EmptyBlock"/-->
+ <module name="LeftCurly"/>
+ <!--module name="NeedBraces"/-->
+ <module name="RightCurly"/>
+
+
+ <!-- Checks for common coding problems -->
+ <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <!--module name="AvoidInlineConditionals"/-->
+ <module name="CovariantEquals"/>
+ <module name="EmptyStatement"/>
+ <!--<module name="EqualsAvoidNull"/>-->
+ <module name="EqualsHashCode"/>
+ <!--module name="HiddenField"/-->
+ <module name="IllegalInstantiation"/>
+ <!--<module name="InnerAssignment"/>-->
+ <!--module name="MagicNumber"/-->
+ <module name="MissingSwitchDefault"/>
+ <module name="RedundantThrows"/>
+ <module name="SimplifyBooleanExpression"/>
+ <module name="SimplifyBooleanReturn"/>
+
+ <!-- Checks for class design -->
+ <!-- See http://checkstyle.sf.net/config_design.html -->
+ <!--module name="DesignForExtension"/-->
+ <!--module name="FinalClass"/-->
+ <!--module name="HideUtilityClassConstructor"/-->
+ <!--module name="InterfaceIsType"/-->
+ <!--module name="VisibilityModifier"/-->
+
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <!--module name="ArrayTypeStyle"/-->
+ <!--module name="FinalParameters"/-->
+ <!--module name="TodoComment"/-->
+ <module name="UpperEll"/>
+ </module>
+</module>
diff --git a/compiler/dependency-reduced-pom.xml b/compiler/dependency-reduced-pom.xml
new file mode 100644
index 0000000..504f9ff
--- /dev/null
+++ b/compiler/dependency-reduced-pom.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <parent>
+ <artifactId>dagger-parent</artifactId>
+ <groupId>com.google.dagger</groupId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>dagger-compiler</artifactId>
+ <name>Dagger Compiler</name>
+ <description>Tools to generate Dagger injection and module adapters from annotated code and validate them.</description>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
+ <annotationProcessor>com.google.auto.service.processor.AutoServiceProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ <execution>
+ <id>default-test-compile</id>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>dagger.internal.codegen.ComponentProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <addTestClassPath>true</addTestClassPath>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <cloneClean>true</cloneClean>
+ <profiles>
+ <profile>!sonatype-oss-release</profile>
+ </profiles>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+ <filterProperties>
+ <dagger.version>${project.version}</dagger.version>
+ <dagger.groupId>${project.groupId}</dagger.groupId>
+ </filterProperties>
+ <streamLogs>true</streamLogs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <excludes>
+ <exclude>com.google.guava</exclude>
+ <exclude>com.google.auto.service</exclude>
+ <exclude>com.google.auto.value</exclude>
+ <exclude>com.google.dagger:dagger</exclude>
+ <exclude>com.google.dagger:dagger-producers</exclude>
+ <exclude>javax.inject</exclude>
+ </excludes>
+ </artifactSet>
+ <relocations>
+ <relocation>
+ <pattern>com.google.auto.common</pattern>
+ <shadedPattern>dagger.shaded.auto.common</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <version>1.0-rc2</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>18.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <version>0.7</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>tools</artifactId>
+ <groupId>com.sun</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>18.0</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>jsr305</artifactId>
+ <groupId>com.google.code.findbugs</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>objenesis</artifactId>
+ <groupId>org.objenesis</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <version>0.26</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/compiler/pom.xml b/compiler/pom.xml
new file mode 100644
index 0000000..72252f1
--- /dev/null
+++ b/compiler/pom.xml
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+ Copyright (C) 2012 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger-compiler</artifactId>
+ <name>Dagger Compiler</name>
+ <description>
+ Tools to generate Dagger injection and module adapters from annotated code and validate them.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto</groupId>
+ <artifactId>auto-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.googlejavaformat</groupId>
+ <artifactId>google-java-format</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <scope>provided</scope> <!-- to leave out of the all-deps jar -->
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <scope>provided</scope> <!-- to leave out of the all-deps jar -->
+ <version>1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <goals><goal>compile</goal></goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
+ <annotationProcessor>com.google.auto.service.processor.AutoServiceProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ <execution>
+ <id>default-test-compile</id>
+ <goals><goal>testCompile</goal></goals>
+ <configuration>
+ <annotationProcessors>
+ <annotationProcessor>dagger.internal.codegen.ComponentProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <configuration>
+ <addTestClassPath>true</addTestClassPath>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <cloneClean>true</cloneClean>
+ <profiles>
+ <profile>!sonatype-oss-release</profile>
+ </profiles>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <localRepositoryPath>${project.build.directory}/it-repo</localRepositoryPath>
+ <filterProperties>
+ <dagger.version>${project.version}</dagger.version>
+ <dagger.groupId>${project.groupId}</dagger.groupId>
+ </filterProperties>
+ <streamLogs>true</streamLogs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <excludes>
+ <!-- guava which has a consistent API and whose public types we vend in producers -->
+ <exclude>com.google.guava</exclude>
+ <!-- annotation processors dagger uses to be built, not to operate -->
+ <exclude>com.google.auto.service</exclude>
+ <exclude>com.google.auto.value</exclude>
+ <!-- projects should depend on api projects directly -->
+ <exclude>com.google.dagger:dagger</exclude>
+ <exclude>com.google.dagger:dagger-producers</exclude>
+ <exclude>javax.inject</exclude>
+ </excludes>
+ </artifactSet>
+ <relocations>
+ <relocation>
+ <pattern>com.google.auto.common</pattern>
+ <shadedPattern>dagger.shaded.auto.common</shadedPattern>
+ </relocation>
+ </relocations>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/functional-tests/pom.xml b/compiler/src/it/functional-tests/pom.xml
new file mode 100644
index 0000000..ce3dd4e
--- /dev/null
+++ b/compiler/src/it/functional-tests/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 Google, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <groupId>dagger.tests</groupId>
+ <artifactId>functional-tests</artifactId>
+ <name>Functional Tests</name>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <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>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject-tck</artifactId>
+ </dependency>
+ <dependency>
+ <!-- For map-bindings -->
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>${auto.value.version}</version>
+ <scope>provided</scope> <!-- to leave out of the all-deps jar -->
+ </dependency>
+ <dependency>
+ <!-- For map-bindings -->
+ <groupId>com.google.auto.factory</groupId>
+ <artifactId>auto-factory</artifactId>
+ <version>${auto.factory.version}</version>
+ <scope>provided</scope> <!-- to leave out of the all-deps jar -->
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>../../../../checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/functional-tests/src/main/java/test/A.java b/compiler/src/it/functional-tests/src/main/java/test/A.java
new file mode 100644
index 0000000..030f855
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/A.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class A {
+ @Inject A() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java b/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java
new file mode 100644
index 0000000..4fb0f78
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/AbstractMembersInjectingBaseClass.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+abstract class AbstractMembersInjectingBaseClass {
+ @Inject Thing thing;
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java b/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java
new file mode 100644
index 0000000..89e94bd
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/AbstractMiddleClassWithoutMembers.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+abstract class AbstractMiddleClassWithoutMembers extends AbstractMembersInjectingBaseClass {
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/B.java b/compiler/src/it/functional-tests/src/main/java/test/B.java
new file mode 100644
index 0000000..dec8e2e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/B.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class B {
+ @Inject B() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java
new file mode 100644
index 0000000..78f77df
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Component;
+
+/**
+ * This component tests behavior equivalent to {@link BasicComponent}, but as an abstract class
+ * rather than an interface.
+ */
+@Component(modules = PrimitivesModule.class)
+abstract class BasicAbstractClassComponent implements BasicComponent {
+ void throwAParty() {
+ throw new RuntimeException("Paaarrrrrtaaaaaaaay!");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java
new file mode 100644
index 0000000..a04607d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Provider;
+
+@Component(modules = PrimitivesModule.class)
+interface BasicComponent extends Injector<Thing> {
+ byte getByte();
+ char getChar();
+ short getShort();
+ int getInt();
+ long getLong();
+ boolean getBoolean();
+ float getFloat();
+ double getDouble();
+
+ Byte getBoxedByte();
+ Character getBoxedChar();
+ Short getBoxedShort();
+ Integer getBoxedInt();
+ Long getBoxedLong();
+ Boolean getBoxedBoolean();
+ Float getBoxedFloat();
+ Double getBoxedDouble();
+
+ Provider<Byte> getByteProvider();
+ Provider<Character> getCharProvider();
+ Provider<Short> getShortProvider();
+ Provider<Integer> getIntProvider();
+ Provider<Long> getLongProvider();
+ Provider<Boolean> getBooleanProvider();
+ Provider<Float> getFloatProvider();
+ Provider<Double> getDoubleProvider();
+
+ byte[] getByteArray();
+ char[] getCharArray();
+ short[] getShortArray();
+ int[] getIntArray();
+ long[] getLongArray();
+ boolean[] getBooleanArray();
+ float[] getFloatArray();
+ double[] getDoubleArray();
+
+ Provider<byte[]> getByteArrayProvider();
+ Provider<char[]> getCharArrayProvider();
+ Provider<short[]> getShortArrayProvider();
+ Provider<int[]> getIntArrayProvider();
+ Provider<long[]> getLongArrayProvider();
+ Provider<boolean[]> getBooleanArrayProvider();
+ Provider<float[]> getFloatArrayProvider();
+ Provider<double[]> getDoubleArrayProvider();
+
+ Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject);
+
+ Thing thing();
+ InjectedThing injectedThing();
+ Provider<InjectedThing> injectedThingProvider();
+ Lazy<InjectedThing> lazyInjectedThing();
+ MembersInjector<InjectedThing> injectedThingMembersInjector();
+
+ TypeWithInheritedMembersInjection typeWithInheritedMembersInjection();
+ MembersInjector<TypeWithInheritedMembersInjection>
+ typeWithInheritedMembersInjectionMembersInjector();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java b/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java
new file mode 100644
index 0000000..4cef79e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BooleanKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface BooleanKey {
+ boolean value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java
new file mode 100644
index 0000000..b30522f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Component;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+@Component(modules = BoundedGenericModule.class)
+interface BoundedGenericComponent {
+ BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
+ bounds1();
+ BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
+ bounds2();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java
new file mode 100644
index 0000000..6bd7be4
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenericModule.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+@Module
+class BoundedGenericModule {
+
+ @Provides
+ Integer provideInteger() {
+ return 1;
+ }
+
+ @Provides
+ Double provideDouble() {
+ return 2d;
+ }
+
+ @Provides
+ ArrayList<String> provideArrayListString() {
+ ArrayList<String> list = new ArrayList<>();
+ list.add("arrayListOfString");
+ return list;
+ }
+
+ @Provides
+ LinkedList<String> provideLinkedListString() {
+ LinkedList<String> list = new LinkedList<>();
+ list.add("linkedListOfString");
+ return list;
+ }
+
+ @Provides
+ LinkedList<CharSequence> provideLinkedListCharSeq() {
+ LinkedList<CharSequence> list = new LinkedList<>();
+ list.add("linkedListOfCharSeq");
+ return list;
+ }
+
+ @Provides
+ @SuppressWarnings("unchecked")
+ LinkedList<Comparable<String>> provideArrayListOfComparableString() {
+ LinkedList<Comparable<String>> list = new LinkedList<>();
+ list.add("arrayListOfComparableOfString");
+ return list;
+ }
+
+ @Provides
+ List<Integer> provideListOfInteger() {
+ LinkedList<Integer> list = new LinkedList<>();
+ list.add(3);
+ return list;
+ }
+
+ @Provides
+ Set<Double> provideSetOfDouble() {
+ Set<Double> set = new HashSet<>();
+ set.add(4d);
+ return set;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java
new file mode 100644
index 0000000..e26d643
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/BoundedGenerics.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+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>,
+ D extends A,
+ E extends Iterable<D>> {
+
+ final A a;
+ final B b;
+ final C c;
+ final D d;
+ final E e;
+
+ @Inject BoundedGenerics(A a, B b, C c, D d, E e) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ this.e = e;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java b/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java
new file mode 100644
index 0000000..8e739bd
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ByteKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface ByteKey {
+ byte value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/CharKey.java b/compiler/src/it/functional-tests/src/main/java/test/CharKey.java
new file mode 100644
index 0000000..a4f4e29
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/CharKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface CharKey {
+ char value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java b/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java
new file mode 100644
index 0000000..09a1e6b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ChildDoubleModule.java
@@ -0,0 +1,21 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+class ChildDoubleModule extends ParentModule<Double, String, List<Double>> {
+
+ @Provides Double provideDouble() {
+ return 3d;
+ }
+
+ @Provides List<Double> provideListOfDouble() {
+ List<Double> list = new ArrayList<>();
+ list.add(4d);
+ return list;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java b/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java
new file mode 100644
index 0000000..ac9c612
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ChildIntegerModule.java
@@ -0,0 +1,21 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+class ChildIntegerModule extends ParentModule<Integer, String, List<Integer>> {
+
+ @Provides Integer provideInteger() {
+ return 1;
+ }
+
+ @Provides List<Integer> provideListOfInteger() {
+ List<Integer> list = new ArrayList<>();
+ list.add(2);
+ return list;
+ }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java b/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java
new file mode 100644
index 0000000..e2e3274
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComplexGenerics.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Lazy;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+class ComplexGenerics {
+
+ final Generic2<Generic<A>> g2ga;
+ final Lazy<Generic2<Generic<A>>> g2gaLazy;
+ final Provider<Generic2<Generic<A>>> g2gaProvider;
+ final Generic2<Generic<B>> g2gb;
+ final Lazy<Generic2<Generic<B>>> g2gbLazy;
+ final Provider<Generic2<Generic<B>>> g2gbProvider;
+ final Generic2<A> g2a;
+ final Generic<Generic2<A>> gg2a;
+ final Generic<Generic2<B>> gg2b;
+
+ @Inject ComplexGenerics(
+ Generic2<Generic<A>> g2ga,
+ Lazy<Generic2<Generic<A>>> g2gaLazy,
+ Provider<Generic2<Generic<A>>> g2gaProvider,
+ Generic2<Generic<B>> g2gb,
+ Lazy<Generic2<Generic<B>>> g2gbLazy,
+ Provider<Generic2<Generic<B>>> g2gbProvider,
+ Generic2<A> g2a,
+ Generic<Generic2<A>> gg2a,
+ Generic<Generic2<B>> gg2b) {
+ this.g2ga = g2ga;
+ this.g2gaLazy = g2gaLazy;
+ this.g2gaProvider = g2gaProvider;
+ this.g2gb = g2gb;
+ this.g2gbLazy = g2gbLazy;
+ this.g2gbProvider = g2gbProvider;
+ this.g2a = g2a;
+ this.gg2a = gg2a;
+ this.gg2b = gg2b;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java
new file mode 100644
index 0000000..6ffe1e0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentDependsOnGeneratedCode.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Component;
+
+@Component
+interface ComponentDependsOnGeneratedCode {
+ NeedsFactory needsFactory();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java
new file mode 100644
index 0000000..f7460c9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCode.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Component;
+
+@Component
+interface ComponentSupertypeDependsOnGeneratedCode
+ extends ComponentSupertypeDependsOnGeneratedCodeInterface {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java
new file mode 100644
index 0000000..fca90e0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ComponentSupertypeDependsOnGeneratedCodeInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+interface ComponentSupertypeDependsOnGeneratedCodeInterface {
+ NeedsFactory_SomethingFactory somethingFactory();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Generic.java b/compiler/src/it/functional-tests/src/main/java/test/Generic.java
new file mode 100644
index 0000000..ee1aa09
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Generic.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+public class Generic<T> {
+ final T t;
+
+ @Inject public Generic(T t) {
+ this.t = t;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Generic2.java b/compiler/src/it/functional-tests/src/main/java/test/Generic2.java
new file mode 100644
index 0000000..4a56df3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Generic2.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+public class Generic2<T> {
+ final T t;
+
+ @Inject Generic2(T t) {
+ this.t = t;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java b/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java
new file mode 100644
index 0000000..5c65dc0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericChild.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class GenericChild<T> extends GenericParent<T, B> {
+
+ A registeredA;
+ T registeredT;
+
+ @Inject GenericChild() {}
+
+ @Inject A a;
+ @Inject T t;
+
+ @Inject void registerA(A a) { this.registeredA = a; }
+ @Inject void registerT(T t) { this.registeredT = t; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java
new file mode 100644
index 0000000..da5b9b5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Component;
+import test.sub.Exposed;
+import test.sub.PublicSubclass;
+
+@Component(modules = {ChildDoubleModule.class, ChildIntegerModule.class})
+interface GenericComponent {
+ ReferencesGeneric referencesGeneric();
+ GenericDoubleReferences<A> doubleGenericA();
+ GenericDoubleReferences<B> doubleGenericB();
+ ComplexGenerics complexGenerics();
+ GenericNoDeps<A> noDepsA();
+ GenericNoDeps<B> noDepsB();
+
+ void injectA(GenericChild<A> childA);
+ void injectB(GenericChild<B> childB);
+
+ Exposed exposed();
+ PublicSubclass publicSubclass();
+
+ Iterable<Integer> iterableInt();
+ Iterable<Double> iterableDouble();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java b/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java
new file mode 100644
index 0000000..6785c7c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericDoubleReferences.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class GenericDoubleReferences<T> {
+ final T t;
+ final T t2;
+ final Thing a;
+ final Thing a2;
+
+ @Inject GenericDoubleReferences(T t, Thing a, T t2, Thing a2) {
+ this.t = t;
+ this.a = a;
+ this.t2 = t2;
+ this.a2 = a2;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java b/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java
new file mode 100644
index 0000000..e065f79
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericNoDeps.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class GenericNoDeps<T> {
+
+ @Inject GenericNoDeps() {}
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java
new file mode 100644
index 0000000..0e01f5f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/GenericParent.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class GenericParent<X, Y> {
+
+ X registeredX;
+ Y registeredY;
+ B registeredB;
+
+
+ @Inject GenericParent() {}
+
+ @Inject X x;
+ @Inject Y y;
+ @Inject B b;
+
+ @Inject void registerX(X x) { this.registeredX = x; }
+ @Inject void registerY(Y y) { this.registeredY = y; }
+ @Inject void registerB(B b) { this.registeredB = b; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java
new file mode 100644
index 0000000..73a46e8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+@SuppressWarnings("unused")
+final class InjectedThing {
+ @Inject byte primitiveByte;
+ @Inject char primitiveChar;
+ @Inject short primitiveShort;
+ @Inject int primitiveInt;
+ @Inject long primitiveLong;
+ @Inject boolean primitiveBoolean;
+ @Inject float primitiveFloat;
+ @Inject double primitiveDouble;
+
+ @Inject Provider<Byte> byteProvider;
+ @Inject Provider<Character> charProvider;
+ @Inject Provider<Short> shortProvider;
+ @Inject Provider<Integer> intProvider;
+ @Inject Provider<Long> longProvider;
+ @Inject Provider<Boolean> booleanProvider;
+ @Inject Provider<Float> floatProvider;
+ @Inject Provider<Double> doubleProvider;
+
+ @Inject Lazy<Byte> lazyByte;
+ @Inject Lazy<Character> lazyChar;
+ @Inject Lazy<Short> lazyShort;
+ @Inject Lazy<Integer> lazyInt;
+ @Inject Lazy<Long> lazyLong;
+ @Inject Lazy<Boolean> lazyBoolean;
+ @Inject Lazy<Float> lazyFloat;
+ @Inject Lazy<Double> lazyDouble;
+
+ @Inject Byte boxedBype;
+ @Inject Character boxedChar;
+ @Inject Short boxedShort;
+ @Inject Integer boxedInt;
+ @Inject Long boxedLong;
+ @Inject Boolean boxedBoolean;
+ @Inject Float boxedFloat;
+ @Inject Double boxedDouble;
+
+ @Inject byte[] byteArray;
+ @Inject char[] charArray;
+ @Inject short[] shortArray;
+ @Inject int[] intArray;
+ @Inject long[] longArray;
+ @Inject boolean[] booleanArray;
+ @Inject float[] floatArray;
+ @Inject double[] doubleArray;
+
+ @Inject Provider<byte[]> byteArrayProvider;
+ @Inject Provider<char[]> charArrayProvider;
+ @Inject Provider<short[]> shortArrayProvider;
+ @Inject Provider<int[]> intArrayProvider;
+ @Inject Provider<long[]> longArrayProvider;
+ @Inject Provider<boolean[]> booleanArrayProvider;
+ @Inject Provider<float[]> floatArrayProvider;
+ @Inject Provider<double[]> doubleArrayProvider;
+
+ @Inject Lazy<byte[]> lazyByteArray;
+ @Inject Lazy<char[]> lazyCharArray;
+ @Inject Lazy<short[]> lazyShortArray;
+ @Inject Lazy<int[]> lazyIntArray;
+ @Inject Lazy<long[]> lazyLongArray;
+ @Inject Lazy<boolean[]> lazyBooleanArray;
+ @Inject Lazy<float[]> lazy;
+ @Inject Lazy<double[]> lazyDoubleArray;
+
+ @Inject Thing thing;
+ @Inject Provider<Thing> thingProvider;
+ @Inject Lazy<Thing> lazyThing;
+ @Inject MembersInjector<Thing> thingMembersInjector;
+
+ @Inject InjectedThing(
+ byte primitiveByte,
+ char primitiveChar,
+ short primitiveShort,
+ int primitiveInt,
+ long primitiveLong,
+ boolean primitiveBoolean,
+ float primitiveFloat,
+ double primitiveDouble,
+
+ Provider<Byte> byteProvider,
+ Provider<Character> charProvider,
+ Provider<Short> shortProvider,
+ Provider<Integer> intProvider,
+ Provider<Long> longProvider,
+ Provider<Boolean> booleanProvider,
+ Provider<Float> floatProvider,
+ Provider<Double> doubleProvider,
+
+ Lazy<Byte> lazyByte,
+ Lazy<Character> lazyChar,
+ Lazy<Short> lazyShort,
+ Lazy<Integer> lazyInt,
+ Lazy<Long> lazyLong,
+ Lazy<Boolean> lazyBoolean,
+ Lazy<Float> lazyFloat,
+ Lazy<Double> lazyDouble,
+
+ Byte boxedBype,
+ Character boxedChar,
+ Short boxedShort,
+ Integer boxedInt,
+ Long boxedLong,
+ Boolean boxedBoolean,
+ Float boxedFloat,
+ Double boxedDouble,
+
+ byte[] byteArray,
+ char[] charArray,
+ short[] shortArray,
+ int[] intArray,
+ long[] longArray,
+ boolean[] booleanArray,
+ float[] floatArray,
+ double[] doubleArray,
+
+ Provider<byte[]> byteArrayProvider,
+ Provider<char[]> charArrayProvider,
+ Provider<short[]> shortArrayProvider,
+ Provider<int[]> intArrayProvider,
+ Provider<long[]> longArrayProvider,
+ Provider<boolean[]> booleanArrayProvider,
+ Provider<float[]> floatArrayProvider,
+ Provider<double[]> doubleArrayProvider,
+
+ Lazy<byte[]> lazyByteArray,
+ Lazy<char[]> lazyCharArray,
+ Lazy<short[]> lazyShortArray,
+ Lazy<int[]> lazyIntArray,
+ Lazy<long[]> lazyLongArray,
+ Lazy<boolean[]> lazyBooleanArray,
+ Lazy<float[]> lazy,
+ Lazy<double[]> lazyDoubleArray,
+
+ Thing thing,
+ Provider<Thing> thingProvider,
+ Lazy<Thing> lazyThing,
+ MembersInjector<Thing> thingMembersInjector) {}
+
+ @Inject void primitiveByte(byte primitiveByte) {}
+ @Inject void primitiveChar(char primitiveChar) {}
+ @Inject void primitiveShort(short primitiveShort) {}
+ @Inject void primitiveInt(int primitiveInt) {}
+ @Inject void primitiveLong(long primitiveLong) {}
+ @Inject void primitiveBoolean(boolean primitiveBoolean) {}
+ @Inject void primitiveFloat(float primitiveFloat) {}
+ @Inject void primitiveDouble(double primitiveDouble) {}
+
+ @Inject void byteProvider(Provider<Byte> byteProvider) {}
+ @Inject void charProvider(Provider<Character> charProvider) {}
+ @Inject void shortProvider(Provider<Short> shortProvider) {}
+ @Inject void intProvider(Provider<Integer> intProvider) {}
+ @Inject void longProvider(Provider<Long> longProvider) {}
+ @Inject void booleanProvider(Provider<Boolean> booleanProvider) {}
+ @Inject void floatProvider(Provider<Float> floatProvider) {}
+ @Inject void doubleProvider(Provider<Double> doubleProvider) {}
+
+ @Inject void lazyByte(Lazy<Byte> lazyByte) {}
+ @Inject void lazyChar(Lazy<Character> lazyChar) {}
+ @Inject void lazyShort(Lazy<Short> lazyShort) {}
+ @Inject void lazyInt(Lazy<Integer> lazyInt) {}
+ @Inject void lazyLong(Lazy<Long> lazyLong) {}
+ @Inject void lazyBoolean(Lazy<Boolean> lazyBoolean) {}
+ @Inject void lazyFloat(Lazy<Float> lazyFloat) {}
+ @Inject void lazyDouble(Lazy<Double> lazyDouble) {}
+
+ @Inject void boxedBype(Byte boxedBype) {}
+ @Inject void boxedChar(Character boxedChar) {}
+ @Inject void boxedShort(Short boxedShort) {}
+ @Inject void boxedInt(Integer boxedInt) {}
+ @Inject void boxedLong(Long boxedLong) {}
+ @Inject void boxedBoolean(Boolean boxedBoolean) {}
+ @Inject void boxedFloat(Float boxedFloat) {}
+ @Inject void boxedDouble(Double boxedDouble) {}
+
+ @Inject void byteArray(byte[] byteArray) {}
+ @Inject void charArray(char[] charArray) {}
+ @Inject void shortArray(short[] shortArray) {}
+ @Inject void intArray(int[] intArray) {}
+ @Inject void longArray(long[] longArray) {}
+ @Inject void booleanArray(boolean[] booleanArray) {}
+ @Inject void floatArray(float[] floatArray) {}
+ @Inject void doubleArray(double[] doubleArray) {}
+
+ @Inject void byteArrayProvider(Provider<byte[]> byteArrayProvider) {}
+ @Inject void charArrayProvider(Provider<char[]> charArrayProvider) {}
+ @Inject void shortArrayProvider(Provider<short[]> shortArrayProvider) {}
+ @Inject void intArrayProvider(Provider<int[]> intArrayProvider) {}
+ @Inject void longArrayProvider(Provider<long[]> longArrayProvider) {}
+ @Inject void booleanArrayProvider(Provider<boolean[]> booleanArrayProvider) {}
+ @Inject void floatArrayProvider(Provider<float[]> floatArrayProvider) {}
+ @Inject void doubleArrayProvider(Provider<double[]> doubleArrayProvider) {}
+
+ @Inject void lazyByteArray(Lazy<byte[]> lazyByteArray) {}
+ @Inject void lazyCharArray(Lazy<char[]> lazyCharArray) {}
+ @Inject void lazyShortArray(Lazy<short[]> lazyShortArray) {}
+ @Inject void lazyIntArray(Lazy<int[]> lazyIntArray) {}
+ @Inject void lazyLongArray(Lazy<long[]> lazyLongArray) {}
+ @Inject void lazyBooleanArray(Lazy<boolean[]> lazyBooleanArray) {}
+ @Inject void lazy(Lazy<float[]> lazy) {}
+ @Inject void lazyDoubleArray(Lazy<double[]> lazyDoubleArray) {}
+
+ @Inject void thing(Thing thing) {}
+ @Inject void thingProvider(Provider<Thing> thingProvider) {}
+ @Inject void lazyThing(Lazy<Thing> lazyThing) {}
+ @Inject void thingMembersInjector(MembersInjector<Thing> thingMembersInjector) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Injector.java b/compiler/src/it/functional-tests/src/main/java/test/Injector.java
new file mode 100644
index 0000000..2a5798a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Injector.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Lazy;
+import dagger.MembersInjector;
+import javax.inject.Provider;
+
+/**
+ * A simple interface that exercises all forms of injection for a given type.
+ */
+interface Injector<T> {
+ T instance();
+ Provider<T> provider();
+ Lazy<T> lazy();
+ MembersInjector<T> membersInjector();
+ void injectMembers(T t);
+ T injectMembersAndReturn(T t);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java
new file mode 100644
index 0000000..ac0624f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingComponent.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Component;
+import dagger.mapkeys.StringKey;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Named;
+import javax.inject.Provider;
+import test.sub.ContributionsModule;
+
+@Component(
+ modules = {
+ MultibindingModule.class,
+ ContributionsModule.class
+ },
+ dependencies = MultibindingDependency.class
+)
+interface MultibindingComponent {
+ Map<String, String> map();
+ Map<String, String[]> mapOfArrays();
+ Map<String, Provider<String>> mapOfProviders();
+ Set<String> mapKeys();
+ Collection<String> mapValues();
+ Set<Integer> set();
+ Map<NestedAnnotationContainer.NestedWrappedKey, String> nestedKeyMap();
+ Map<Class<? extends Number>, String> numberClassKeyMap();
+ Map<Class<?>, String> classKeyMap();
+ Map<Long, String> longKeyMap();
+ Map<Integer, String> integerKeyMap();
+ Map<Short, String> shortKeyMap();
+ Map<Byte, String> byteKeyMap();
+ Map<Boolean, String> booleanKeyMap();
+ Map<Character, String> characterKeyMap();
+ Map<StringKey, String> unwrappedAnnotationKeyMap();
+ Map<WrappedAnnotationKey, String> wrappedAnnotationKeyMap();
+ @Named("complexQualifier") Set<String> complexQualifierStringSet();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java
new file mode 100644
index 0000000..a92e029
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingDependency.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+interface MultibindingDependency {
+ double doubleDependency();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java
new file mode 100644
index 0000000..4a7577e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/MultibindingModule.java
@@ -0,0 +1,181 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.IntKey;
+import dagger.mapkeys.LongKey;
+import dagger.mapkeys.StringKey;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class MultibindingModule {
+ @Provides(type = MAP)
+ @StringKey("foo")
+ static String provideFooKey(double doubleDependency) {
+ return "foo value";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("bar")
+ static String provideBarKey() {
+ return "bar value";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("foo")
+ static String[] provideFooArrayValue(double doubleDependency) {
+ return new String[] {"foo1", "foo2"};
+ }
+
+ @Provides(type = MAP)
+ @StringKey("bar")
+ static String[] provideBarArrayValue() {
+ return new String[] {"bar1", "bar2"};
+ }
+
+ @Provides(type = SET)
+ static int provideFiveToSet() {
+ return 5;
+ }
+
+ @Provides(type = SET)
+ static int provideSixToSet() {
+ return 6;
+ }
+
+ @Provides
+ static Set<String> provideMapKeys(Map<String, Provider<String>> map) {
+ return map.keySet();
+ }
+
+ @Provides
+ static Collection<String> provideMapValues(Map<String, String> map) {
+ return map.values();
+ }
+
+ @Provides(type = MAP)
+ @NestedAnnotationContainer.NestedWrappedKey(Integer.class)
+ static String valueForInteger() {
+ return "integer";
+ }
+
+ @Provides(type = MAP)
+ @NestedAnnotationContainer.NestedWrappedKey(Long.class)
+ static String valueForLong() {
+ return "long";
+ }
+
+ @Provides(type = MAP)
+ @ClassKey(Integer.class)
+ static String valueForClassInteger() {
+ return "integer";
+ }
+
+ @Provides(type = MAP)
+ @ClassKey(Long.class)
+ static String valueForClassLong() {
+ return "long";
+ }
+
+ @Provides(type = MAP)
+ @NumberClassKey(BigDecimal.class)
+ static String valueForNumberClassBigDecimal() {
+ return "bigdecimal";
+ }
+
+ @Provides(type = MAP)
+ @NumberClassKey(BigInteger.class)
+ static String valueForNumberClassBigInteger() {
+ return "biginteger";
+ }
+
+ @Provides(type = MAP)
+ @LongKey(100)
+ static String valueFor100Long() {
+ return "100 long";
+ }
+
+ @Provides(type = MAP)
+ @IntKey(100)
+ static String valueFor100Int() {
+ return "100 int";
+ }
+
+ @Provides(type = MAP)
+ @ShortKey(100)
+ static String valueFor100Short() {
+ return "100 short";
+ }
+
+ @Provides(type = MAP)
+ @ByteKey(100)
+ static String valueFor100Byte() {
+ return "100 byte";
+ }
+
+ @Provides(type = MAP)
+ @BooleanKey(true)
+ static String valueForTrue() {
+ return "true";
+ }
+
+ @Provides(type = MAP)
+ @CharKey('a')
+ static String valueForA() {
+ return "a char";
+ }
+
+ @Provides(type = MAP)
+ @CharKey('\n')
+ static String valueForNewline() {
+ return "newline char";
+ }
+
+ @Provides(type = MAP)
+ @UnwrappedAnnotationKey(@StringKey("foo\n"))
+ static String valueForUnwrappedAnnotationKeyFoo() {
+ return "foo annotation";
+ }
+
+ @Provides(type = MAP)
+ @WrappedAnnotationKey(
+ value = @StringKey("foo"),
+ integers = {1, 2, 3},
+ annotations = {},
+ classes = {Long.class, Integer.class}
+ )
+ static String valueForWrappedAnnotationKeyFoo() {
+ return "wrapped foo annotation";
+ }
+
+ @Provides(type = SET)
+ @Named("complexQualifier")
+ static String valueForComplexQualifierSet() {
+ return "foo";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java b/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java
new file mode 100644
index 0000000..b789073
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NeedsFactory.java
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import com.google.auto.factory.AutoFactory;
+import javax.inject.Inject;
+
+class NeedsFactory {
+ @Inject NeedsFactory(NeedsFactory_SomethingFactory somethingFactory) {}
+
+ @AutoFactory
+ static class Something {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java b/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java
new file mode 100644
index 0000000..c57b4ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NestedAnnotationContainer.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+public final class NestedAnnotationContainer {
+
+ @MapKey(unwrapValue = false)
+ @interface NestedWrappedKey {
+ Class<?> value();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java b/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java
new file mode 100644
index 0000000..43a088c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.Component;
+import javax.inject.Inject;
+import test.sub.OtherThing;
+
+@Component(dependencies = {NonComponentDependencyComponent.ThingComponent.class})
+interface NonComponentDependencyComponent {
+ ThingTwo thingTwo();
+
+ static class ThingTwo {
+ @SuppressWarnings("unused")
+ @Inject
+ ThingTwo(
+ Thing thing,
+ NonComponentDependencyComponent nonComponentDependencyComponent,
+ NonComponentDependencyComponent.ThingComponent thingComponent) {}
+ }
+
+ // A non-component interface which this interface depends upon.
+ interface ThingComponent {
+ Thing thing();
+ }
+
+ // The implementation for that interface.
+ static class ThingComponentImpl implements ThingComponent {
+ @Override
+ public Thing thing() {
+ return new Thing(new OtherThing(1));
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java b/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java
new file mode 100644
index 0000000..4164ae5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/NumberClassKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface NumberClassKey {
+ Class<? extends Number> value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java b/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java
new file mode 100644
index 0000000..c7fabdb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/OuterClassBar.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Component;
+
+final class OuterClassBar {
+ @Component(modules = PrimitivesModule.class)
+ interface NestedComponent {
+ InjectedThing injectedThing();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java b/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java
new file mode 100644
index 0000000..86f963f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/OuterClassFoo.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import dagger.Component;
+
+final class OuterClassFoo {
+ @Component(modules = PrimitivesModule.class)
+ interface NestedComponent {
+ Thing thing();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java b/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java
new file mode 100644
index 0000000..a161aba
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ParentModule.java
@@ -0,0 +1,18 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.ArrayList;
+import java.util.List;
+
+@Module
+abstract class ParentModule<A extends Number & Comparable<A>, B, C extends Iterable<A>> {
+ @Provides Iterable<A> provideIterableOfAWithC(A a, C c) {
+ List<A> list = new ArrayList<>();
+ list.add(a);
+ for (A elt : c) {
+ list.add(elt);
+ }
+ return list;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java b/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java
new file mode 100644
index 0000000..acbf271
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/PrimitivesModule.java
@@ -0,0 +1,93 @@
+package test;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class PrimitivesModule {
+ static final byte BOUND_BYTE = -41;
+ static final char BOUND_CHAR = 'g';
+ static final short BOUND_SHORT = 21840;
+ static final int BOUND_INT = 1894833693;
+ static final long BOUND_LONG = -4369839828653523584L;
+ static final boolean BOUND_BOOLEAN = true;
+ static final float BOUND_FLOAT = (float) 0.9964542;
+ static final double BOUND_DOUBLE = 0.12681322049667765;
+
+ /*
+ * While we can't ensure that these constants stay constant, this is a test so we're just going to
+ * keep our fingers crossed that we're not going to be jerks.
+ */
+ static final byte[] BOUND_BYTE_ARRAY = {1, 2, 3};
+ static final char[] BOUND_CHAR_ARRAY = {'g', 'a', 'k'};
+ static final short[] BOUND_SHORT_ARRAY = {2, 4};
+ static final int[] BOUND_INT_ARRAY = {3, 1, 2};
+ static final long[] BOUND_LONG_ARRAY = {1, 1, 2, 3, 5};
+ static final boolean[] BOUND_BOOLEAN_ARRAY = {false, true, false, false};
+ static final float[] BOUND_FLOAT_ARRAY = {(float) 0.1, (float) 0.01, (float) 0.001};
+ static final double[] BOUND_DOUBLE_ARRAY = {0.2, 0.02, 0.002};
+
+ @Provides static byte provideByte() {
+ return BOUND_BYTE;
+ }
+
+ @Provides static char provideChar() {
+ return BOUND_CHAR;
+ }
+
+ @Provides static short provideShort() {
+ return BOUND_SHORT;
+ }
+
+ @Provides static int provideInt() {
+ return BOUND_INT;
+ }
+
+ @Provides static long provideLong() {
+ return BOUND_LONG;
+ }
+
+ @Provides static boolean provideBoolean() {
+ return BOUND_BOOLEAN;
+ }
+
+ @Provides static float provideFloat() {
+ return BOUND_FLOAT;
+ }
+
+ @Provides static double boundDouble() {
+ return BOUND_DOUBLE;
+ }
+
+ @Provides static byte[] provideByteArray() {
+ return BOUND_BYTE_ARRAY;
+ }
+
+ @Provides static char[] provideCharArray() {
+ return BOUND_CHAR_ARRAY;
+ }
+
+ @Provides static short[] provideShortArray() {
+ return BOUND_SHORT_ARRAY;
+ }
+
+ @Provides static int[] provideIntArray() {
+ return BOUND_INT_ARRAY;
+ }
+
+ @Provides static long[] provideLongArray() {
+ return BOUND_LONG_ARRAY;
+ }
+
+ @Provides static boolean[] provideBooleanArray() {
+ return BOUND_BOOLEAN_ARRAY;
+ }
+
+ @Provides static float[] provideFloatArray() {
+ return BOUND_FLOAT_ARRAY;
+ }
+
+ @Provides static double[] boundDoubleArray() {
+ return BOUND_DOUBLE_ARRAY;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java b/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java
new file mode 100644
index 0000000..812c45d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ReferencesGeneric.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+class ReferencesGeneric {
+ final Generic<A> genericA;
+
+ @Inject ReferencesGeneric(Generic<A> genericA) {
+ this.genericA = genericA;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java b/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java
new file mode 100644
index 0000000..37d68e0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ScopedGeneric.java
@@ -0,0 +1,12 @@
+package test;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+class ScopedGeneric<T> {
+ final T t;
+ @Inject ScopedGeneric(T t) {
+ this.t = t;
+ }
+}
\ No newline at end of file
diff --git a/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java b/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java
new file mode 100644
index 0000000..01b3aa9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/ShortKey.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+
+@MapKey(unwrapValue = true)
+@interface ShortKey {
+ short value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java
new file mode 100644
index 0000000..44a2cb5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/SingletonGenericComponent.java
@@ -0,0 +1,13 @@
+package test;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Singleton
+@Component
+interface SingletonGenericComponent {
+
+ ScopedGeneric<A> scopedGenericA();
+ ScopedGeneric<B> scopedGenericB();
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/Thing.java b/compiler/src/it/functional-tests/src/main/java/test/Thing.java
new file mode 100644
index 0000000..46cbdc9
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/Thing.java
@@ -0,0 +1,23 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import javax.inject.Inject;
+import test.sub.OtherThing;
+
+final class Thing {
+ @Inject Thing(@SuppressWarnings("unused") OtherThing unused) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java b/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java
new file mode 100644
index 0000000..587baad
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/TypeWithInheritedMembersInjection.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import javax.inject.Inject;
+
+final class TypeWithInheritedMembersInjection extends AbstractMiddleClassWithoutMembers {
+ @Inject TypeWithInheritedMembersInjection() {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java b/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java
new file mode 100644
index 0000000..21ed958
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/UnwrappedAnnotationKey.java
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+import dagger.mapkeys.StringKey;
+
+@MapKey(unwrapValue = true)
+@interface UnwrappedAnnotationKey {
+ StringKey value();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java b/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java
new file mode 100644
index 0000000..5d6e86d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/WrappedAnnotationKey.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import dagger.MapKey;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.StringKey;
+
+@MapKey(unwrapValue = false)
+@interface WrappedAnnotationKey {
+ StringKey value();
+ int[] integers();
+ ClassKey[] annotations();
+ Class<? extends Number>[] classes();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java
new file mode 100644
index 0000000..8b85d60
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ByteModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class ByteModule {
+ final byte b;
+
+ ByteModule(byte b) {
+ this.b = b;
+ }
+
+ @Provides byte b() { return b; }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java
new file mode 100644
index 0000000..93fd59d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/DepComponent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+
+@Component
+interface DepComponent {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java
new file mode 100644
index 0000000..2dec4a7
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/DoubleModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class DoubleModule {
+ @Provides
+ double d() {
+ return 4.2d;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java
new file mode 100644
index 0000000..309e7ee
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/FloatModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class FloatModule {
+ @Provides
+ float f() {
+ return 5.5f;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java
new file mode 100644
index 0000000..af196ee
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/GenericParent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+interface GenericParent<B> {
+ B subcomponentBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java
new file mode 100644
index 0000000..8cbf67b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/Grandchild.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = IntModuleIncludingDoubleAndFloat.class)
+interface Grandchild {
+ int i();
+ String s();
+
+ @Subcomponent.Builder
+ interface Builder {
+ Grandchild build();
+ Builder set(IntModuleIncludingDoubleAndFloat intModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java b/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java
new file mode 100644
index 0000000..5e3a928
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/IntModuleIncludingDoubleAndFloat.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module(includes = { DoubleModule.class, FloatModule.class })
+class IntModuleIncludingDoubleAndFloat {
+ final int integer;
+
+ IntModuleIncludingDoubleAndFloat(int integer) {
+ this.integer = integer;
+ }
+
+ @Provides
+ int integer() {
+ return integer;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java
new file mode 100644
index 0000000..c16c9c7
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/LongModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class LongModule {
+ @Provides
+ long l() {
+ return 6L;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java
new file mode 100644
index 0000000..690c91a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleChild.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Subcomponent;
+
+@MiddleScope
+@Subcomponent(modules = StringModule.class)
+interface MiddleChild {
+ String s();
+
+ Grandchild.Builder grandchildBuilder();
+
+ RequiresSubcomponentBuilder<Grandchild.Builder> requiresGrandchildBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ MiddleChild build();
+ Builder set(StringModule stringModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java
new file mode 100644
index 0000000..e2fbcaa
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/MiddleScope.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Scope
+@Retention(RUNTIME)
+@interface MiddleScope {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java b/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java
new file mode 100644
index 0000000..28e43ba
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/OtherMiddleChild.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Subcomponent;
+
+@MiddleScope
+@Subcomponent(modules = {StringModule.class, LongModule.class})
+interface OtherMiddleChild {
+ long l();
+ String s();
+
+ Grandchild.Builder grandchildBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ OtherMiddleChild build();
+ Builder set(StringModule stringModule);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java
new file mode 100644
index 0000000..584eff6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Singleton
+@Component
+interface ParentComponent {
+ TestChildComponentWithBuilderAbstractClass.Builder childAbstractClassBuilder();
+ TestChildComponentWithBuilderInterface.Builder childInterfaceBuilder();
+
+ MiddleChild.Builder middleBuilder();
+ OtherMiddleChild.Builder otherBuilder();
+
+ RequiresSubcomponentBuilder<MiddleChild.Builder> requiresMiddleChildBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java
new file mode 100644
index 0000000..474c617
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/ParentOfGenericComponent.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = StringModule.class)
+@Singleton
+interface ParentOfGenericComponent extends GenericParent<Grandchild.Builder> {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/RequiresSubcomponentBuilder.java b/compiler/src/it/functional-tests/src/main/java/test/builder/RequiresSubcomponentBuilder.java
new file mode 100644
index 0000000..ee99632
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/RequiresSubcomponentBuilder.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+class RequiresSubcomponentBuilder<B> {
+ private final Provider<B> subcomponentBuilderProvider;
+ private final B subcomponentBuilder;
+
+ @Inject
+ RequiresSubcomponentBuilder(Provider<B> subcomponentBuilderProvider, B subcomponentBuilder) {
+ this.subcomponentBuilderProvider = subcomponentBuilderProvider;
+ this.subcomponentBuilder = subcomponentBuilder;
+ }
+
+ Provider<B> subcomponentBuilderProvider() {
+ return subcomponentBuilderProvider;
+ }
+
+ B subcomponentBuilder() {
+ return subcomponentBuilder;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java b/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java
new file mode 100644
index 0000000..3b979a5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/StringModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class StringModule {
+ final String string;
+
+ StringModule(String string) {
+ this.string = string;
+ }
+
+ @Provides
+ String string() {
+ return string;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java
new file mode 100644
index 0000000..8f39c14
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderAbstractClass.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
+ LongModule.class, ByteModule.class})
+interface TestChildComponentWithBuilderAbstractClass {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+ byte b();
+
+ abstract class SharedBuilder<B, C, M1, M2> {
+ abstract C build(); // Test resolving return type of build()
+ abstract B setM1(M1 m1); // Test resolving return type & param of setter
+ abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ abstract void setM3(DoubleModule doubleModule); // Test being overridden
+ abstract SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test returning supertype.
+ }
+
+ @Subcomponent.Builder
+ abstract class Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderAbstractClass,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariance
+ @Override abstract void setM3(DoubleModule doubleModule); // Test simple overrides allowed
+ abstract void set(ByteModule byteModule);
+
+ // Note we're missing LongModule -- it's implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java
new file mode 100644
index 0000000..2add34e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestChildComponentWithBuilderInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
+ LongModule.class, ByteModule.class})
+interface TestChildComponentWithBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+ byte b();
+
+ interface SharedBuilder<B, C, M1, M2> {
+ C build(); // Test resolving return type of build()
+ B setM1(M1 m1); // Test resolving return type & param of setter
+ SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ void setM3(DoubleModule doubleModule); // Test being overridden
+ SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
+ }
+
+ @Subcomponent.Builder
+ interface Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderInterface,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
+ @Override void setM3(DoubleModule doubleModule); // Test simple overrides allowed
+ void set(ByteModule byteModule);
+
+ // Note we're missing LongModule -- it's implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java
new file mode 100644
index 0000000..5eef53f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderAbstractClass.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+abstract class TestComponentWithBuilderAbstractClass {
+
+ static Builder builder() {
+ return DaggerTestComponentWithBuilderAbstractClass.builder();
+ }
+
+ abstract String s();
+ abstract int i();
+ abstract long l();
+ abstract float f();
+ abstract double d();
+
+
+ static abstract class SharedBuilder {
+ // Make sure we use the overriding signature.
+ abstract Object build();
+
+ Object stringModule(@SuppressWarnings("unused") StringModule stringModule) {
+ return null;
+ }
+
+ SharedBuilder ignoredLongModule(@SuppressWarnings("unused") LongModule longModule) {
+ return null;
+ }
+
+ }
+
+ @Component.Builder
+ static abstract class Builder extends SharedBuilder {
+ @Override abstract TestComponentWithBuilderAbstractClass build(); // Narrowing return type
+ @Override abstract Builder stringModule(StringModule stringModule); // Make abstract & narrow
+ abstract Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
+ abstract void doubleModule(DoubleModule doubleModule); // Module w/o args
+ abstract void depComponent(DepComponent depComponent);
+
+ Builder ignoredIntModule(
+ @SuppressWarnings("unused") IntModuleIncludingDoubleAndFloat intModule) {
+ return null;
+ }
+
+ // Note we're missing LongModule & FloatModule -- they/re implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java
new file mode 100644
index 0000000..55214f8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithBuilderInterface.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ interface SharedBuilder {
+ // Make sure we use the overriding signature.
+ Object build();
+ Object stringModule(StringModule m1);
+ }
+
+ @Component.Builder
+ interface Builder extends SharedBuilder {
+ @Override TestComponentWithBuilderInterface build(); // Narrowing return type
+ @Override Builder stringModule(StringModule stringModule); // Narrowing return type
+ Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
+ void doubleModule(DoubleModule doubleModule); // Module w/o args
+ void depComponent(DepComponent depComponent);
+
+ // Note we're missing LongModule & FloatModule -- they/re implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java
new file mode 100644
index 0000000..8032185
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderAbstractClass.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithGenericBuilderAbstractClass {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ static abstract class SharedBuilder<B, C, M1, M2> {
+ abstract C build(); // Test resolving return type of build()
+ abstract B setM1(M1 m1); // Test resolving return type & param of setter
+ abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ abstract void doubleModule(DoubleModule doubleModule); // Test being overridden
+ abstract SharedBuilder<B, C, M1, M2> depComponent(FloatModule floatModule); // Test return type
+ }
+
+ @Component.Builder
+ static abstract class Builder extends SharedBuilder<Builder,
+ TestComponentWithGenericBuilderAbstractClass, StringModule,
+ IntModuleIncludingDoubleAndFloat> {
+ @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
+ @Override abstract void doubleModule(DoubleModule module3); // Test simple overrides allowed
+ abstract void depComponent(DepComponent depComponent);
+
+ // Note we're missing LongModule & FloatModule -- they're implicit
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java
new file mode 100644
index 0000000..f63e3ec
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/builder/TestComponentWithGenericBuilderInterface.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import dagger.Component;
+
+@Component(
+ modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
+ dependencies = DepComponent.class)
+interface TestComponentWithGenericBuilderInterface {
+ String s();
+ int i();
+ long l();
+ float f();
+ double d();
+
+ interface SharedBuilder<B, C, M1, M2> {
+ C build(); // Test resolving return type of build()
+ B setM1(M1 m1); // Test resolving return type & param of setter
+ SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
+ void doubleModule(DoubleModule doubleModule); // Test being overridden
+ SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
+ }
+
+ @Component.Builder
+ interface Builder extends SharedBuilder<Builder, TestComponentWithGenericBuilderInterface,
+ StringModule, IntModuleIncludingDoubleAndFloat> {
+ @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides allowed
+ @Override void doubleModule(DoubleModule module3); // Test simple overrides allowed
+ void depComponent(DepComponent depComponent);
+
+ // Note we're missing M5 -- that's implicit.
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java b/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java
new file mode 100644
index 0000000..8d67d92
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/cycle/Cycles.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.cycle;
+
+import dagger.Component;
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+import dagger.mapkeys.StringKey;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import static dagger.Provides.Type.MAP;
+
+/**
+ * Cycle classes used for testing cyclic dependencies.
+ * A <- (E <- D <- B <- C <- Provider<A>, Lazy<A>), (B <- C <- Provider<A>, Lazy<A>)
+ * S <- Provider<S>, Lazy<S>
+ *
+ * @author Tony Bentancur
+ * @since 2.0
+ */
+
+final class Cycles {
+ private Cycles() {}
+
+ static class A {
+ public final B b;
+ public final E e;
+
+ @Inject
+ A(E e, B b) {
+ this.e = e;
+ this.b = b;
+ }
+ }
+
+ static class B {
+ public final C c;
+
+ @Inject
+ B(C c) {
+ this.c = c;
+ }
+ }
+
+ static class C {
+ public final Provider<A> aProvider;
+ @Inject public Lazy<A> aLazy;
+
+ @Inject
+ C(Provider<A> aProvider) {
+ this.aProvider = aProvider;
+ }
+ }
+
+ static class D {
+ public final B b;
+
+ @Inject
+ D(B b) {
+ this.b = b;
+ }
+ }
+
+ static class E {
+ public final D d;
+
+ @Inject
+ E(D d) {
+ this.d = d;
+ }
+ }
+
+ static class S {
+ public final Provider<S> sProvider;
+ @Inject public Lazy<S> sLazy;
+
+ @Inject
+ S(Provider<S> sProvider) {
+ this.sProvider = sProvider;
+ }
+ }
+
+ static class X {
+ public final Y y;
+
+ @Inject
+ X(Y y) {
+ this.y = y;
+ }
+ }
+
+ static class Y {
+ public final Map<String, Provider<X>> mapOfProvidersOfX;
+ public final Map<String, Provider<Y>> mapOfProvidersOfY;
+
+ @Inject
+ Y(Map<String, Provider<X>> mapOfProvidersOfX, Map<String, Provider<Y>> mapOfProvidersOfY) {
+ this.mapOfProvidersOfX = mapOfProvidersOfX;
+ this.mapOfProvidersOfY = mapOfProvidersOfY;
+ }
+ }
+
+ @Module
+ static class CycleMapModule {
+ @Provides(type = MAP)
+ @StringKey("X")
+ static X x(X x) {
+ return x;
+ }
+
+ @Provides(type = MAP)
+ @StringKey("Y")
+ static Y y(Y y) {
+ return y;
+ }
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component(modules = CycleMapModule.class)
+ interface CycleMapComponent {
+ Y y();
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface CycleComponent {
+ A a();
+
+ C c();
+
+ ChildCycleComponent child();
+ }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface SelfCycleComponent {
+ S s();
+ }
+
+ @Subcomponent
+ interface ChildCycleComponent {
+ @SuppressWarnings("dependency-cycle")
+ A a();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java b/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java
new file mode 100644
index 0000000..b4f61e0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/cycle/LongCycle.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.cycle;
+
+import dagger.Component;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+final class LongCycle {
+ static class Class1 { @Inject Class1(Class2 class2) {} }
+ static class Class2 { @Inject Class2(Class3 class3) {} }
+ static class Class3 { @Inject Class3(Class4 class4) {} }
+ static class Class4 { @Inject Class4(Class5 class5) {} }
+ static class Class5 { @Inject Class5(Class6 class6) {} }
+ static class Class6 { @Inject Class6(Class7 class7) {} }
+ static class Class7 { @Inject Class7(Class8 class8) {} }
+ static class Class8 { @Inject Class8(Class9 class9) {} }
+ static class Class9 { @Inject Class9(Class10 class10) {} }
+ static class Class10 { @Inject Class10(Class11 class11) {} }
+ static class Class11 { @Inject Class11(Class12 class12) {} }
+ static class Class12 { @Inject Class12(Class13 class13) {} }
+ static class Class13 { @Inject Class13(Class14 class14) {} }
+ static class Class14 { @Inject Class14(Class15 class15) {} }
+ static class Class15 { @Inject Class15(Class16 class16) {} }
+ static class Class16 { @Inject Class16(Class17 class17) {} }
+ static class Class17 { @Inject Class17(Class18 class18) {} }
+ static class Class18 { @Inject Class18(Class19 class19) {} }
+ static class Class19 { @Inject Class19(Class20 class20) {} }
+ static class Class20 { @Inject Class20(Class21 class21) {} }
+ static class Class21 { @Inject Class21(Class22 class22) {} }
+ static class Class22 { @Inject Class22(Class23 class23) {} }
+ static class Class23 { @Inject Class23(Class24 class24) {} }
+ static class Class24 { @Inject Class24(Class25 class25) {} }
+ static class Class25 { @Inject Class25(Class26 class26) {} }
+ static class Class26 { @Inject Class26(Class27 class27) {} }
+ static class Class27 { @Inject Class27(Class28 class28) {} }
+ static class Class28 { @Inject Class28(Class29 class29) {} }
+ static class Class29 { @Inject Class29(Class30 class30) {} }
+ static class Class30 { @Inject Class30(Class31 class31) {} }
+ static class Class31 { @Inject Class31(Class32 class32) {} }
+ static class Class32 { @Inject Class32(Class33 class33) {} }
+ static class Class33 { @Inject Class33(Class34 class34) {} }
+ static class Class34 { @Inject Class34(Class35 class35) {} }
+ static class Class35 { @Inject Class35(Class36 class36) {} }
+ static class Class36 { @Inject Class36(Class37 class37) {} }
+ static class Class37 { @Inject Class37(Class38 class38) {} }
+ static class Class38 { @Inject Class38(Class39 class39) {} }
+ static class Class39 { @Inject Class39(Class40 class40) {} }
+ static class Class40 { @Inject Class40(Class41 class41) {} }
+ static class Class41 { @Inject Class41(Class42 class42) {} }
+ static class Class42 { @Inject Class42(Class43 class43) {} }
+ static class Class43 { @Inject Class43(Class44 class44) {} }
+ static class Class44 { @Inject Class44(Class45 class45) {} }
+ static class Class45 { @Inject Class45(Class46 class46) {} }
+ static class Class46 { @Inject Class46(Class47 class47) {} }
+ static class Class47 { @Inject Class47(Class48 class48) {} }
+ static class Class48 { @Inject Class48(Class49 class49) {} }
+ static class Class49 { @Inject Class49(Class50 class50) {} }
+ static class Class50 { @Inject Class50(Class51 class51) {} }
+ static class Class51 { @Inject Class51(Class52 class52) {} }
+ static class Class52 { @Inject Class52(Class53 class53) {} }
+ static class Class53 { @Inject Class53(Class54 class54) {} }
+ static class Class54 { @Inject Class54(Class55 class55) {} }
+ static class Class55 { @Inject Class55(Class56 class56) {} }
+ static class Class56 { @Inject Class56(Class57 class57) {} }
+ static class Class57 { @Inject Class57(Class58 class58) {} }
+ static class Class58 { @Inject Class58(Class59 class59) {} }
+ static class Class59 { @Inject Class59(Class60 class60) {} }
+ static class Class60 { @Inject Class60(Class61 class61) {} }
+ static class Class61 { @Inject Class61(Class62 class62) {} }
+ static class Class62 { @Inject Class62(Class63 class63) {} }
+ static class Class63 { @Inject Class63(Class64 class64) {} }
+ static class Class64 { @Inject Class64(Class65 class65) {} }
+ static class Class65 { @Inject Class65(Class66 class66) {} }
+ static class Class66 { @Inject Class66(Class67 class67) {} }
+ static class Class67 { @Inject Class67(Class68 class68) {} }
+ static class Class68 { @Inject Class68(Class69 class69) {} }
+ static class Class69 { @Inject Class69(Class70 class70) {} }
+ static class Class70 { @Inject Class70(Class71 class71) {} }
+ static class Class71 { @Inject Class71(Class72 class72) {} }
+ static class Class72 { @Inject Class72(Class73 class73) {} }
+ static class Class73 { @Inject Class73(Class74 class74) {} }
+ static class Class74 { @Inject Class74(Class75 class75) {} }
+ static class Class75 { @Inject Class75(Class76 class76) {} }
+ static class Class76 { @Inject Class76(Class77 class77) {} }
+ static class Class77 { @Inject Class77(Class78 class78) {} }
+ static class Class78 { @Inject Class78(Class79 class79) {} }
+ static class Class79 { @Inject Class79(Class80 class80) {} }
+ static class Class80 { @Inject Class80(Class81 class81) {} }
+ static class Class81 { @Inject Class81(Class82 class82) {} }
+ static class Class82 { @Inject Class82(Class83 class83) {} }
+ static class Class83 { @Inject Class83(Class84 class84) {} }
+ static class Class84 { @Inject Class84(Class85 class85) {} }
+ static class Class85 { @Inject Class85(Class86 class86) {} }
+ static class Class86 { @Inject Class86(Class87 class87) {} }
+ static class Class87 { @Inject Class87(Class88 class88) {} }
+ static class Class88 { @Inject Class88(Class89 class89) {} }
+ static class Class89 { @Inject Class89(Class90 class90) {} }
+ static class Class90 { @Inject Class90(Class91 class91) {} }
+ static class Class91 { @Inject Class91(Class92 class92) {} }
+ static class Class92 { @Inject Class92(Class93 class93) {} }
+ static class Class93 { @Inject Class93(Class94 class94) {} }
+ static class Class94 { @Inject Class94(Class95 class95) {} }
+ static class Class95 { @Inject Class95(Class96 class96) {} }
+ static class Class96 { @Inject Class96(Class97 class97) {} }
+ static class Class97 { @Inject Class97(Class98 class98) {} }
+ static class Class98 { @Inject Class98(Class99 class99) {} }
+ static class Class99 { @Inject Class99(Class100 class100) {} }
+ static class Class100 { @Inject Class100(Class101 class101) {} }
+ static class Class101 { @Inject Class101(Provider<Class1> class1Provider) {} }
+
+ @SuppressWarnings("dependency-cycle")
+ @Component
+ interface LongCycleComponent {
+ Class1 class1();
+ }
+
+ private LongCycle() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java
new file mode 100644
index 0000000..22efcf1
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+class ChildOfArrayOfParentOfStringArray extends
+ MembersInjectGenericParent<MembersInjectGenericParent<String[]>[]> {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java
new file mode 100644
index 0000000..e01c1c2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+class ChildOfPrimitiveIntArray extends MembersInjectGenericParent<int[]> {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java
new file mode 100644
index 0000000..8ec943b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+class ChildOfStringArray extends MembersInjectGenericParent<String[]> {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java
new file mode 100644
index 0000000..9ab8c19
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+import dagger.Component;
+
+@Component(modules = {MembersInjectModule.class})
+interface MembersInjectComponent {
+
+ void inject(ChildOfStringArray subfoo);
+ void inject(ChildOfArrayOfParentOfStringArray subfoo);
+ void inject(ChildOfPrimitiveIntArray subfoo);
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java
new file mode 100644
index 0000000..064b886
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+import javax.inject.Inject;
+
+class MembersInjectGenericParent<T> {
+
+ @Inject T t;
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java
new file mode 100644
index 0000000..a6c1fad
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class MembersInjectModule {
+
+ @Provides String[] provideStringArray() { return new String[10]; }
+
+ @Provides int[] provideIntArray() { return new int[10]; }
+
+ @SuppressWarnings("unchecked")
+ @Provides MembersInjectGenericParent<String[]>[] provideFooArrayOfStringArray() { return new MembersInjectGenericParent[10]; }
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java b/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java
new file mode 100644
index 0000000..108a1b5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/membersinject/NonRequestedChild.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+import javax.inject.Inject;
+
+/**
+ * A class that should not be requested by any component, to ensure that we still generate a members
+ * injector for it.
+ */
+class NonRequestedChild extends MembersInjectGenericParent<String> {
+ @Inject
+ NonRequestedChild() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java
new file mode 100644
index 0000000..3c88415
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/FooComponent.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage;
+
+import dagger.Component;
+import java.util.Set;
+import test.multipackage.a.AModule;
+import test.multipackage.sub.FooChildComponent;
+
+/**
+ * A component that tests the interaction between subcomponents, multiple packages, and
+ * multibindings. Specifically, we want:
+ * <ul>
+ * <li>A set binding with some contributions in the parent component, and some in the subcomponent.
+ * <li>The contributions come from different packages, but not the package of either component.
+ * <li>The set binding is requested in the subcomponent through a binding from a separate package.
+ * <li>No binding in the subcomponent, that's in the subcomponent's package, directly uses any
+ * binding from the component's package.
+ * </ul>
+ */
+// NOTE(beder): Be careful about changing any bindings in either this component or the subcomponent.
+// Even adding a binding might stop this test from testing what it's supposed to test.
+@Component(modules = {AModule.class})
+interface FooComponent {
+ Set<String> setOfString();
+
+ FooChildComponent fooChildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java
new file mode 100644
index 0000000..85ce40a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/MembersInjectionVisibilityComponent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage;
+
+import dagger.Component;
+import test.multipackage.a.AGrandchild;
+import test.multipackage.a.AModule;
+import test.multipackage.a.AParent;
+import test.multipackage.b.BChild;
+
+/**
+ * A component that tests members injection across packages and subclasses.
+ */
+@Component(modules = {AModule.class})
+public interface MembersInjectionVisibilityComponent {
+ void inject(AParent aParent);
+
+ void inject(BChild aChild);
+
+ void inject(AGrandchild aGrandchild);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java
new file mode 100644
index 0000000..8f0f1f3
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AGrandchild.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.a;
+
+import javax.inject.Inject;
+import test.multipackage.b.BChild;
+
+public class AGrandchild extends BChild {
+
+ @Inject APackagePrivateObject aGrandchildField;
+
+ private APackagePrivateObject aGrandchildMethod;
+
+ @Inject
+ void aGrandchildMethod(APackagePrivateObject aGrandchildMethod) {
+ this.aGrandchildMethod = aGrandchildMethod;
+ }
+
+ @Override
+ @Inject
+ protected void aParentMethod(APublicObject aParentMethod) {
+ super.aParentMethod(aParentMethod);
+ }
+
+ @Override
+ protected void aChildMethod(APublicObject aChildMethod) {
+ super.aChildMethod(aChildMethod);
+ }
+
+ public APackagePrivateObject aGrandchildField() {
+ return aGrandchildField;
+ }
+
+ public APackagePrivateObject aGrandchildMethod() {
+ return aGrandchildMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java
new file mode 100644
index 0000000..d62506a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.a;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class AModule {
+ @Provides(type = SET) String provideString() {
+ return "a";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java
new file mode 100644
index 0000000..d604133
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APackagePrivateObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.a;
+
+import javax.inject.Inject;
+
+class APackagePrivateObject {
+
+ @Inject
+ APackagePrivateObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java
new file mode 100644
index 0000000..4c91a6f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/AParent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.a;
+
+import javax.inject.Inject;
+
+public class AParent {
+
+ @Inject APackagePrivateObject aParentField;
+
+ private APublicObject aParentMethod;
+
+ @Inject
+ protected void aParentMethod(APublicObject aParentMethod) {
+ this.aParentMethod = aParentMethod;
+ }
+
+ public APackagePrivateObject aParentField() {
+ return aParentField;
+ }
+
+ public APublicObject aParentMethod() {
+ return aParentMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java
new file mode 100644
index 0000000..90357f6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/a/APublicObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.a;
+
+import javax.inject.Inject;
+
+public class APublicObject {
+
+ @Inject
+ APublicObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java
new file mode 100644
index 0000000..188d120
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BChild.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.b;
+
+import javax.inject.Inject;
+import test.multipackage.a.AParent;
+import test.multipackage.a.APublicObject;
+
+public class BChild extends AParent {
+
+ @Inject BPackagePrivateObject aChildField;
+
+ private APublicObject aChildMethod;
+
+ @Inject
+ protected void aChildMethod(APublicObject aChildMethod) {
+ this.aChildMethod = aChildMethod;
+ }
+
+ @Override
+ protected void aParentMethod(APublicObject aParentMethod) {
+ super.aParentMethod(aParentMethod);
+ }
+
+ public BPackagePrivateObject aChildField() {
+ return aChildField;
+ }
+
+ public APublicObject aChildMethod() {
+ return aChildMethod;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java
new file mode 100644
index 0000000..4d817f1
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.b;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class BModule {
+ @Provides(type = SET) String provideString() {
+ return "b";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java
new file mode 100644
index 0000000..c397a02
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/b/BPackagePrivateObject.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.multipackage.b;
+
+import javax.inject.Inject;
+
+class BPackagePrivateObject {
+
+ @Inject
+ BPackagePrivateObject() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java
new file mode 100644
index 0000000..e608afb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/c/CModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.c;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class CModule {
+ @Provides(type = SET) String provideString() {
+ return "c";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java
new file mode 100644
index 0000000..51f8ace
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/d/DModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.d;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+public final class DModule {
+ @Provides(type = SET) String provideString() {
+ return "d";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java
new file mode 100644
index 0000000..35f5862
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/foo/Foo.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.foo;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+public final class Foo<T> {
+ public final Set<String> strings;
+
+ @Inject Foo(Set<String> strings) {
+ this.strings = strings;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java
new file mode 100644
index 0000000..16a61dd
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/grandsub/FooGrandchildComponent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.grandsub;
+
+import dagger.Subcomponent;
+import test.multipackage.d.DModule;
+import test.multipackage.foo.Foo;
+
+@Subcomponent(modules = DModule.class)
+public interface FooGrandchildComponent {
+ Foo<FooGrandchildComponent> foo();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java
new file mode 100644
index 0000000..9050fcd
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/multipackage/sub/FooChildComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.multipackage.sub;
+
+import dagger.Subcomponent;
+import test.multipackage.b.BModule;
+import test.multipackage.c.CModule;
+import test.multipackage.foo.Foo;
+import test.multipackage.grandsub.FooGrandchildComponent;
+
+@Subcomponent(modules = {BModule.class, CModule.class})
+public interface FooChildComponent {
+ Foo<FooChildComponent> foo();
+
+ FooGrandchildComponent fooGrandchildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java
new file mode 100644
index 0000000..a8a5724
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponent.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test.nullables;
+
+import javax.inject.Provider;
+
+import dagger.Component;
+
+@Component(modules = NullModule.class)
+interface NullComponent {
+ NullFoo nullFoo();
+ @Nullable String string();
+ Provider<String> stringProvider();
+ Number number();
+ Provider<Number> numberProvider();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java
new file mode 100644
index 0000000..05093ed
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullComponentWithDependency.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test.nullables;
+
+import javax.inject.Provider;
+
+import dagger.Component;
+
+@Component(dependencies = NullComponent.class)
+interface NullComponentWithDependency {
+ @Nullable String string();
+ Provider<String> stringProvider();
+ Number number();
+ Provider<Number> numberProvider();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java
new file mode 100644
index 0000000..9ed4b5d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullFoo.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test.nullables;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+class NullFoo {
+ final String string;
+ final Provider<String> stringProvider;
+ final Number number;
+ final Provider<Number> numberProvider;
+
+ @Inject
+ NullFoo(@Nullable String string,
+ Provider<String> stringProvider,
+ Number number,
+ Provider<Number> numberProvider) {
+ this.string = string;
+ this.stringProvider = stringProvider;
+ this.number = number;
+ this.numberProvider = numberProvider;
+ }
+
+ String methodInjectedString;
+ Provider<String> methodInjectedStringProvider;
+ Number methodInjectedNumber;
+ Provider<Number> methodInjectedNumberProvider;
+ @Inject void inject(@Nullable String string,
+ Provider<String> stringProvider,
+ Number number,
+ Provider<Number> numberProvider) {
+ this.methodInjectedString = string;
+ this.methodInjectedStringProvider = stringProvider;
+ this.methodInjectedNumber = number;
+ this.methodInjectedNumberProvider = numberProvider;
+ }
+
+ @Nullable @Inject String fieldInjectedString;
+ @Inject Provider<String> fieldInjectedStringProvider;
+ @Inject Number fieldInjectedNumber;
+ @Inject Provider<Number> fieldInjectedNumberProvider;
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java
new file mode 100644
index 0000000..652d5eb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/NullModule.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test.nullables;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+class NullModule {
+ Number numberValue = null;
+
+ @Nullable
+ @Provides
+ String provideNullableString() {
+ return null;
+ }
+
+ @Provides
+ Number provideNumber() {
+ return numberValue;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java b/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java
new file mode 100644
index 0000000..8677640
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/nullables/Nullable.java
@@ -0,0 +1,3 @@
+package test.nullables;
+
+@interface Nullable {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java
new file mode 100644
index 0000000..f47d36c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/AllStaticModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.staticprovides;
+
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+import static java.util.Collections.emptySet;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+
+@Module
+final class AllStaticModule {
+ @Provides(type = SET) static String contributeString() {
+ return AllStaticModule.class + ".contributeString";
+ }
+
+ @Provides(type = SET_VALUES) static Set<Integer> contibuteEmptyIntegerSet() {
+ return emptySet();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java
new file mode 100644
index 0000000..53ee14d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/SomeStaticModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.staticprovides;
+
+import static dagger.Provides.Type.SET;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class SomeStaticModule {
+ @Provides(type = SET) static String contributeStringFromAStaticMethod() {
+ return SomeStaticModule.class + ".contributeStringFromAStaticMethod";
+ }
+
+ @Provides(type = SET) String contributeStringFromAnInstanceMethod() {
+ return SomeStaticModule.class + ".contributeStringFromAnInstanceMethod";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java
new file mode 100644
index 0000000..4be51ed
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.staticprovides;
+
+import dagger.Component;
+import java.util.Set;
+
+/**
+ * A simple component that demonstrates both static and non-static provides methods.
+ */
+@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
+interface StaticTestComponent {
+ Set<String> getMultiboundStrings();
+ Set<Integer> getMultiboundIntegers();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java
new file mode 100644
index 0000000..d778fc5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/staticprovides/StaticTestComponentWithBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.staticprovides;
+
+import dagger.Component;
+
+/**
+ * A simple component that demonstrates both static and non-static provides methods with a builder.
+ */
+@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
+interface StaticTestComponentWithBuilder extends StaticTestComponent {
+ @Component.Builder
+ interface Builder {
+ Builder allStaticModule(AllStaticModule allStaticModule);
+ Builder someStaticModule(SomeStaticModule someStaticModule);
+ StaticTestComponentWithBuilder build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java b/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java
new file mode 100644
index 0000000..b10ac45
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/ContributionsModule.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.sub;
+
+import dagger.Module;
+import dagger.Provides;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+
+@Module
+public final class ContributionsModule {
+ @Provides(type = SET) int contributeAnInt(double doubleDependency) {
+ return 1742;
+ }
+
+ @Provides(type = SET) int contributeAnotherInt() {
+ return 832;
+ }
+
+ @Provides(type = SET_VALUES) Set<Integer> contributeSomeInts() {
+ return Collections.unmodifiableSet(new LinkedHashSet<Integer>(Arrays.asList(-1, -90, -17)));
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java b/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java
new file mode 100644
index 0000000..9195b33
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/Exposed.java
@@ -0,0 +1,19 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+import test.Generic2;
+
+public class Exposed {
+
+ @Inject public Generic2<PackagePrivate> gpp2;
+ @Inject public Generic2<PackagePrivateContainer.PublicEnclosed> gppc2;
+
+ public Generic<PackagePrivate> gpp;
+ public Generic<PackagePrivateContainer.PublicEnclosed> gppc;
+
+ @Inject Exposed(Generic<PackagePrivate> gpp, Generic<PackagePrivateContainer.PublicEnclosed> gppc) {
+ this.gpp = gpp;
+ this.gppc = gppc;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java b/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java
new file mode 100644
index 0000000..9493517
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/OtherThing.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.sub;
+
+import javax.inject.Inject;
+
+public final class OtherThing {
+ @Inject public OtherThing(int i) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java
new file mode 100644
index 0000000..9af646a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivate.java
@@ -0,0 +1,7 @@
+package test.sub;
+
+import javax.inject.Inject;
+
+class PackagePrivate {
+ @Inject PackagePrivate() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java
new file mode 100644
index 0000000..765b015
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PackagePrivateContainer.java
@@ -0,0 +1,9 @@
+package test.sub;
+
+import javax.inject.Inject;
+
+class PackagePrivateContainer {
+ public static class PublicEnclosed {
+ @Inject PublicEnclosed() {}
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java
new file mode 100644
index 0000000..586d55d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass.java
@@ -0,0 +1,10 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+
+public class PublicSubclass extends Generic<PackagePrivate> {
+ @Inject public PublicSubclass(PackagePrivate pp) {
+ super(pp);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java
new file mode 100644
index 0000000..c356fa8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/sub/PublicSubclass2.java
@@ -0,0 +1,10 @@
+package test.sub;
+
+import javax.inject.Inject;
+import test.Generic;
+
+public class PublicSubclass2 extends Generic<PackagePrivateContainer.PublicEnclosed> {
+ @Inject public PublicSubclass2(PackagePrivateContainer.PublicEnclosed pp) {
+ super(pp);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java
new file mode 100644
index 0000000..8aaa015
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/AnInterface.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+interface AnInterface {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java
new file mode 100644
index 0000000..8ae1474
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/BoundAsSingleton.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Retention(RUNTIME)
+@Qualifier
+@interface BoundAsSingleton {}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java
new file mode 100644
index 0000000..2529433
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildAbstractClassComponent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {ChildModule.class, StaticChildModule.class})
+abstract class ChildAbstractClassComponent implements ChildComponent {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java
new file mode 100644
index 0000000..d3c28f2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Subcomponent;
+import java.util.Set;
+import javax.inject.Provider;
+
+@Subcomponent(modules = {ChildModule.class, StaticChildModule.class})
+interface ChildComponent {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ RequiresSingletons requiresSingleton();
+
+ Set<Object> objectSet();
+
+ GrandchildComponent newGrandchildComponent();
+
+ Object object();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java
new file mode 100644
index 0000000..905c689
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = {
+ ChildModule.class,
+ ChildModuleWithParameters.class,
+ ChildModuleWithState.class})
+interface ChildComponentRequiringModules {
+ int getInt();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java
new file mode 100644
index 0000000..9ed266a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentWithMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = ChildMultibindingModule.class)
+interface ChildComponentWithMultibindings {
+ RequiresMultibindingsInChild requiresMultibindingsInChild();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java
new file mode 100644
index 0000000..ef28bd4
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class ChildModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in child";
+ }
+ };
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java
new file mode 100644
index 0000000..e18b4a6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+
+/**
+ * This is a module that can't be constructed with a default constructor.
+ */
+@Module
+final class ChildModuleWithParameters {
+ public ChildModuleWithParameters(@SuppressWarnings("unused") Object whatever) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java
new file mode 100644
index 0000000..5908a00
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * This is a module that can be constructed with a default constructor, but has state, so callers
+ * might want to pass a reference anyway.
+ */
+@Module
+final class ChildModuleWithState {
+ private int i = 0;
+
+ @Provides int provideInt() {
+ return i++;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java
new file mode 100644
index 0000000..ae02b9e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildMultibindingModule.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.StringKey;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class ChildMultibindingModule {
+
+ @Provides(type = SET)
+ static Object childObject() {
+ return "object provided by child";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("child key")
+ static Object childKeyObject() {
+ return "object in child";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java
new file mode 100644
index 0000000..5580ab8
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GenericParentComponent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+interface GenericParentComponent<B> {
+ B subcomponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java
new file mode 100644
index 0000000..9f724ed
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Subcomponent;
+import java.util.Set;
+import javax.inject.Provider;
+
+@Subcomponent(modules = GrandchildModule.class)
+interface GrandchildComponent {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ RequiresSingletons requiresSingleton();
+
+ Set<Object> objectSet();
+
+ NeedsAnInterface needsAnInterface();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java
new file mode 100644
index 0000000..b288541
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/GrandchildModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class GrandchildModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in grandchild";
+ }
+ };
+ }
+
+ @Provides AnInterface provideAnInterface(ImplementsAnInterface implementsAnInterface) {
+ return implementsAnInterface;
+ }
+
+ @Provides NeedsAnInterface provideNeedsAnInterface(AnInterface anInterface) {
+ return new NeedsAnInterface(anInterface);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java
new file mode 100644
index 0000000..ff3170c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ImplementsAnInterface.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import javax.inject.Inject;
+
+class ImplementsAnInterface implements AnInterface {
+ @Inject ImplementsAnInterface() {}
+}
+
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java
new file mode 100644
index 0000000..bccde85
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/NeedsAnInterface.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+class NeedsAnInterface {
+ NeedsAnInterface(AnInterface anInterface) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java
new file mode 100644
index 0000000..ebb067d
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = ParentModule.class)
+@Singleton
+interface ParentComponent extends ParentGetters {
+ ChildComponent newChildComponent();
+
+ ChildAbstractClassComponent newChildAbstractClassComponent();
+
+ ChildComponentRequiringModules newChildComponentRequiringModules(
+ ChildModuleWithParameters cmwp,
+ ChildModuleWithState childModuleWithState);
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java
new file mode 100644
index 0000000..46fe883
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Component;
+
+@Component(modules = ParentMultibindingModule.class)
+interface ParentComponentWithMultibindings extends ParentComponentWithoutMultibindings {
+ RequiresMultibindingsInParent requiresMultibindingsInParent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java
new file mode 100644
index 0000000..3d4431c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponentWithoutMultibindings.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Component;
+
+@Component(modules = ParentMultibindingModule.class)
+interface ParentComponentWithoutMultibindings {
+ ChildComponentWithMultibindings childComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java
new file mode 100644
index 0000000..3ff855a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentGetters.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Provider;
+
+interface ParentGetters {
+ Provider<UnscopedType> getUnscopedTypeProvider();
+
+ Set<Object> objectSet();
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java
new file mode 100644
index 0000000..dbe1a53
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentModule.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class ParentModule {
+ @Provides(type = SET) Object provideUnscopedObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "unscoped in parent";
+ }
+ };
+ }
+
+ @Provides(type = SET) @Singleton Object provideSingletonObject() {
+ return new Object() {
+ @Override public String toString() {
+ return "singleton";
+ }
+ };
+ }
+
+ @Provides @Singleton @BoundAsSingleton UnscopedType provideUnscopedTypeBoundAsSingleton(
+ UnscopedType unscopedType) {
+ return unscopedType;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java
new file mode 100644
index 0000000..e4ec173
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentMultibindingModule.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.mapkeys.StringKey;
+
+import static dagger.Provides.Type.MAP;
+import static dagger.Provides.Type.SET;
+
+@Module
+class ParentMultibindingModule {
+
+ @Provides(type = SET)
+ static Object provideObject() {
+ return "object provided by parent";
+ }
+
+ @Provides(type = SET)
+ static String provideString() {
+ return "string provided by parent";
+ }
+
+ @Provides(type = SET)
+ static RequiresMultiboundObjects requiresMultiboundObjects(
+ RequiresMultiboundObjects requiresMultiboundObjects) {
+ return requiresMultiboundObjects;
+ }
+
+ @Provides(type = MAP)
+ @StringKey("parent key")
+ static String parentKeyString() {
+ return "string in parent";
+ }
+
+ @Provides(type = MAP)
+ @StringKey("parent key")
+ static Object parentKeyObject() {
+ return "object in parent";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java
new file mode 100644
index 0000000..bf85537
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentOfGenericComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = ParentModule.class)
+@Singleton
+interface ParentOfGenericComponent extends GenericParentComponent<ChildComponent>, ParentGetters {
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java
new file mode 100644
index 0000000..4ec0469
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInChild.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultibindingsInChild extends RequiresMultibindingsInParent {
+
+ @Inject
+ RequiresMultibindingsInChild(
+ RequiresMultiboundObjects requiresMultiboundObjects,
+ RequiresMultiboundStrings requiresMultiboundStrings,
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects) {
+ super(requiresMultiboundObjects, requiresMultiboundStrings, setOfRequiresMultiboundObjects);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java
new file mode 100644
index 0000000..a48d38b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultibindingsInParent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultibindingsInParent {
+ private final RequiresMultiboundObjects requiresMultiboundObjects;
+ private final RequiresMultiboundStrings requiresMultiboundStrings;
+ private final Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects;
+
+ @Inject
+ RequiresMultibindingsInParent(
+ RequiresMultiboundObjects requiresMultiboundObjects,
+ RequiresMultiboundStrings requiresMultiboundStrings,
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects) {
+ this.requiresMultiboundObjects = requiresMultiboundObjects;
+ this.requiresMultiboundStrings = requiresMultiboundStrings;
+ this.setOfRequiresMultiboundObjects = setOfRequiresMultiboundObjects;
+ }
+
+ RequiresMultiboundObjects requiresMultiboundObjects() {
+ return requiresMultiboundObjects;
+ }
+
+ RequiresMultiboundStrings requiresMultiboundStrings() {
+ return requiresMultiboundStrings;
+ }
+
+ Set<RequiresMultiboundObjects> setOfRequiresMultiboundObjects() {
+ return setOfRequiresMultiboundObjects;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java
new file mode 100644
index 0000000..d787153
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundObjects.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultiboundObjects {
+ private final Set<Object> setOfObjects;
+ private final Map<String, Object> mapOfObjects;
+
+ @Inject
+ RequiresMultiboundObjects(Set<Object> setOfObjects, Map<String, Object> mapOfObjects) {
+ this.setOfObjects = setOfObjects;
+ this.mapOfObjects = mapOfObjects;
+ }
+
+ Set<Object> setOfObjects() {
+ return setOfObjects;
+ }
+
+ Map<String, Object> mapOfObjects() {
+ return mapOfObjects;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java
new file mode 100644
index 0000000..410bdf2
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresMultiboundStrings.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+
+class RequiresMultiboundStrings {
+ private final Set<String> setOfStrings;
+ private final Map<String, String> mapOfStrings;
+
+ @Inject
+ RequiresMultiboundStrings(Set<String> setOfStrings, Map<String, String> mapOfStrings) {
+ this.setOfStrings = setOfStrings;
+ this.mapOfStrings = mapOfStrings;
+ }
+
+ Set<String> setOfStrings() {
+ return setOfStrings;
+ }
+
+ Map<String, String> mapOfStrings() {
+ return mapOfStrings;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java
new file mode 100644
index 0000000..2d40538
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/RequiresSingletons.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import javax.inject.Inject;
+
+final class RequiresSingletons {
+ private final SingletonType singletonType;
+ private final UnscopedType unscopedTypeBoundAsSingleton;
+
+ @Inject RequiresSingletons(SingletonType singletonType,
+ @BoundAsSingleton UnscopedType unscopedTypeBoundAsSingleton) {
+ this.singletonType = singletonType;
+ this.unscopedTypeBoundAsSingleton = unscopedTypeBoundAsSingleton;
+ }
+
+ SingletonType singletonType() {
+ return singletonType;
+ }
+
+ UnscopedType unscopedTypeBoundAsSingleton() {
+ return unscopedTypeBoundAsSingleton;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java
new file mode 100644
index 0000000..663e858
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/SingletonType.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+final class SingletonType {
+ @Inject SingletonType() {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/StaticChildModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/StaticChildModule.java
new file mode 100644
index 0000000..f7fd490
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/StaticChildModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class StaticChildModule {
+ private StaticChildModule() {}
+
+ @Provides static Object provideStaticObject() {
+ return "static";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java
new file mode 100644
index 0000000..89c0085
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/UnscopedType.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import javax.inject.Inject;
+
+final class UnscopedType {
+ @Inject UnscopedType(@SuppressWarnings("unused") SingletonType singletonType) {}
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java
new file mode 100644
index 0000000..b95502c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ChildComponent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = test.subcomponent.hiding.b.CommonModuleName.class)
+interface ChildComponent {
+ //ensure that t.s.h.a.CommonName gets bound in this component
+ test.subcomponent.hiding.a.CommonName aCommonName();
+ //ensure that t.s.h.b.CommonName gets bound in this component
+ test.subcomponent.hiding.b.CommonName bCommonName();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java
new file mode 100644
index 0000000..d7c66a6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/ParentComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+@Component(modules = test.subcomponent.hiding.a.CommonModuleName.class)
+@Singleton
+interface ParentComponent {
+ // ensure that t.s.h.a.CommonName gets bound in this component
+ test.subcomponent.hiding.a.CommonName aCommonName();
+
+ ChildComponent newChildComponent();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java
new file mode 100644
index 0000000..ad69289
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonModuleName.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding.a;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class CommonModuleName {
+ @Provides String provideString() {
+ return "a";
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java
new file mode 100644
index 0000000..b2aefda
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/a/CommonName.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding.a;
+
+import javax.inject.Inject;
+
+public final class CommonName {
+ private final String s;
+
+ @Inject CommonName(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public String toString() {
+ return s;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java
new file mode 100644
index 0000000..66deab5
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonModuleName.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding.b;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class CommonModuleName {
+ @Provides int provideString() {
+ return 1;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java
new file mode 100644
index 0000000..023cbdb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/hiding/b/CommonName.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding.b;
+
+import javax.inject.Inject;
+
+public final class CommonName {
+ private final int i;
+
+ @Inject CommonName(int i) {
+ this.i = i;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(i);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java
new file mode 100644
index 0000000..2dd8d20
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInChild.java
@@ -0,0 +1,5 @@
+package test.subcomponent.repeat;
+
+abstract class OnlyUsedInChild {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java
new file mode 100644
index 0000000..cc22b1e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/OnlyUsedInParent.java
@@ -0,0 +1,5 @@
+package test.subcomponent.repeat;
+
+abstract class OnlyUsedInParent {
+
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java
new file mode 100644
index 0000000..f0af002
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/ParentComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.repeat;
+
+import dagger.Component;
+import java.util.Set;
+
+@Component(modules = RepeatedModule.class)
+interface ParentComponent {
+ Object state();
+
+ String getString();
+ Set<String> getMultiboundStrings();
+ OnlyUsedInParent getOnlyUsedInParent();
+
+ SubcomponentWithRepeatedModule.Builder newChildComponentBuilder();
+
+ SubcomponentWithoutRepeatedModule newChildComponentWithoutRepeatedModule();
+
+ @Component.Builder
+ interface Builder {
+ Builder repeatedModule(RepeatedModule repeatedModule);
+
+ ParentComponent build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java
new file mode 100644
index 0000000..d099751
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/RepeatedModule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.repeat;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class RepeatedModule {
+ private final Object state = new Object();
+
+ @Provides
+ Object state() {
+ return state;
+ }
+
+ @Provides
+ static String provideString() {
+ return "a string";
+ }
+
+ @Provides(type = SET)
+ static String contributeString() {
+ return "a string in a set";
+ }
+
+ @Provides
+ static OnlyUsedInParent provideOnlyUsedInParent() {
+ return new OnlyUsedInParent() {};
+ }
+
+ @Provides
+ static OnlyUsedInChild provideOnlyUsedInChild() {
+ return new OnlyUsedInChild() {};
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java
new file mode 100644
index 0000000..279bc95
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithRepeatedModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.repeat;
+
+import dagger.Subcomponent;
+import java.util.Set;
+
+@Subcomponent(modules = RepeatedModule.class)
+interface SubcomponentWithRepeatedModule {
+ Object state();
+
+ String getString();
+
+ Set<String> getMultiboundStrings();
+
+ OnlyUsedInChild getOnlyUsedInChild();
+
+ @Subcomponent.Builder
+ interface Builder {
+ Builder repeatedModule(RepeatedModule repeatedModule);
+
+ SubcomponentWithRepeatedModule build();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
new file mode 100644
index 0000000..e63c9a0
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.repeat;
+
+import dagger.Subcomponent;
+
+@Subcomponent
+interface SubcomponentWithoutRepeatedModule {
+ SubcomponentWithRepeatedModule.Builder newGrandchildBuilder();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java
new file mode 100644
index 0000000..bc78517
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/CarModule.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Car;
+import org.atinject.tck.auto.Convertible;
+
+@Module
+class CarModule {
+ @Provides
+ Car provideConvertible(Convertible convertible) {
+ return convertible;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java b/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java
new file mode 100644
index 0000000..e42532e
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/CarShop.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.Component;
+import org.atinject.tck.auto.Car;
+import javax.inject.Singleton;
+
+@Singleton
+@Component(
+ modules = {
+ CarModule.class,
+ TireModule.class,
+ SeatModule.class,
+ EngineModule.class,
+ FuelTankModule.class
+ }
+)
+public interface CarShop {
+ @SuppressWarnings("dependency-cycle")
+ Car make();
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java
new file mode 100644
index 0000000..577fb5b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/EngineModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Engine;
+import org.atinject.tck.auto.V8Engine;
+
+@Module
+public class EngineModule {
+ @Provides
+ Engine provideEngine(MembersInjector<V8Engine> injector) {
+ // This is provided because V8Engine has no @Inject constructor and Dagger requires an @Inject
+ // constructor, however this is a TCK supplied class that we prefer to leave unmodified.
+ V8Engine engine = new V8Engine();
+ injector.injectMembers(engine);
+ return engine;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java
new file mode 100644
index 0000000..931556c
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/FuelTankModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.FuelTank;
+
+@Module
+class FuelTankModule {
+ @Provides
+ FuelTank provideFuelTank() {
+ return new FuelTank();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java
new file mode 100644
index 0000000..5c6b729
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/SeatModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Drivers;
+import org.atinject.tck.auto.DriversSeat;
+import org.atinject.tck.auto.Seat;
+
+@Module
+class SeatModule {
+ @Provides
+ @Drivers
+ Seat provideSeat(DriversSeat seat) {
+ return seat;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java b/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java
new file mode 100644
index 0000000..914a6d6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/main/java/test/tck/TireModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import dagger.Module;
+import dagger.Provides;
+import org.atinject.tck.auto.Tire;
+import org.atinject.tck.auto.accessories.SpareTire;
+import javax.inject.Named;
+
+@Module
+class TireModule {
+ @Provides
+ @Named("spare")
+ Tire provideTire(SpareTire sparetire) {
+ return sparetire;
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java
new file mode 100644
index 0000000..fe9c6af
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (C) 2014 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+import static com.google.common.truth.Truth.assertThat;
+import static test.PrimitivesModule.BOUND_BOOLEAN;
+import static test.PrimitivesModule.BOUND_BOOLEAN_ARRAY;
+import static test.PrimitivesModule.BOUND_BYTE;
+import static test.PrimitivesModule.BOUND_BYTE_ARRAY;
+import static test.PrimitivesModule.BOUND_CHAR;
+import static test.PrimitivesModule.BOUND_CHAR_ARRAY;
+import static test.PrimitivesModule.BOUND_DOUBLE;
+import static test.PrimitivesModule.BOUND_DOUBLE_ARRAY;
+import static test.PrimitivesModule.BOUND_FLOAT;
+import static test.PrimitivesModule.BOUND_FLOAT_ARRAY;
+import static test.PrimitivesModule.BOUND_INT;
+import static test.PrimitivesModule.BOUND_INT_ARRAY;
+import static test.PrimitivesModule.BOUND_LONG;
+import static test.PrimitivesModule.BOUND_LONG_ARRAY;
+import static test.PrimitivesModule.BOUND_SHORT;
+import static test.PrimitivesModule.BOUND_SHORT_ARRAY;
+
+@RunWith(Theories.class)
+public class BasicTest {
+ @DataPoint
+ public static final BasicComponent basicComponent = DaggerBasicComponent.create();
+ @DataPoint
+ public static final BasicComponent abstractClassBasicComponent =
+ DaggerBasicAbstractClassComponent.create();
+
+ @Theory public void primitives(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByte()).isEqualTo(BOUND_BYTE);
+ assertThat(basicComponent.getChar()).isEqualTo(BOUND_CHAR);
+ assertThat(basicComponent.getShort()).isEqualTo(BOUND_SHORT);
+ assertThat(basicComponent.getInt()).isEqualTo(BOUND_INT);
+ assertThat(basicComponent.getLong()).isEqualTo(BOUND_LONG);
+ assertThat(basicComponent.getBoolean()).isEqualTo(BOUND_BOOLEAN);
+ assertThat(basicComponent.getFloat()).isEqualTo(BOUND_FLOAT);
+ assertThat(basicComponent.getDouble()).isEqualTo(BOUND_DOUBLE);
+ }
+
+ @Theory public void boxedPrimitives(BasicComponent basicComponent) {
+ assertThat(basicComponent.getBoxedByte()).isEqualTo(new Byte(BOUND_BYTE));
+ assertThat(basicComponent.getBoxedChar()).isEqualTo(new Character(BOUND_CHAR));
+ assertThat(basicComponent.getBoxedShort()).isEqualTo(new Short(BOUND_SHORT));
+ assertThat(basicComponent.getBoxedInt()).isEqualTo(new Integer(BOUND_INT));
+ assertThat(basicComponent.getBoxedLong()).isEqualTo(new Long(BOUND_LONG));
+ assertThat(basicComponent.getBoxedBoolean()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+ assertThat(basicComponent.getBoxedFloat()).isEqualTo(new Float(BOUND_FLOAT));
+ assertThat(basicComponent.getBoxedDouble()).isEqualTo(new Double(BOUND_DOUBLE));
+ }
+
+ @Theory public void boxedPrimitiveProviders(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteProvider().get()).isEqualTo(new Byte(BOUND_BYTE));
+ assertThat(basicComponent.getCharProvider().get()).isEqualTo(new Character(BOUND_CHAR));
+ assertThat(basicComponent.getShortProvider().get()).isEqualTo(new Short(BOUND_SHORT));
+ assertThat(basicComponent.getIntProvider().get()).isEqualTo(new Integer(BOUND_INT));
+ assertThat(basicComponent.getLongProvider().get()).isEqualTo(new Long(BOUND_LONG));
+ assertThat(basicComponent.getBooleanProvider().get()).isEqualTo(new Boolean(BOUND_BOOLEAN));
+ assertThat(basicComponent.getFloatProvider().get()).isEqualTo(new Float(BOUND_FLOAT));
+ assertThat(basicComponent.getDoubleProvider().get()).isEqualTo(new Double(BOUND_DOUBLE));
+ }
+
+ @Theory public void primitiveArrays(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteArray()).isSameAs(BOUND_BYTE_ARRAY);
+ assertThat(basicComponent.getCharArray()).isSameAs(BOUND_CHAR_ARRAY);
+ assertThat(basicComponent.getShortArray()).isSameAs(BOUND_SHORT_ARRAY);
+ assertThat(basicComponent.getIntArray()).isSameAs(BOUND_INT_ARRAY);
+ assertThat(basicComponent.getLongArray()).isSameAs(BOUND_LONG_ARRAY);
+ assertThat(basicComponent.getBooleanArray()).isSameAs(BOUND_BOOLEAN_ARRAY);
+ assertThat(basicComponent.getFloatArray()).isSameAs(BOUND_FLOAT_ARRAY);
+ assertThat(basicComponent.getDoubleArray()).isSameAs(BOUND_DOUBLE_ARRAY);
+ }
+
+ @Theory public void primitiveArrayProviders(BasicComponent basicComponent) {
+ assertThat(basicComponent.getByteArrayProvider().get()).isSameAs(BOUND_BYTE_ARRAY);
+ assertThat(basicComponent.getCharArrayProvider().get()).isSameAs(BOUND_CHAR_ARRAY);
+ assertThat(basicComponent.getShortArrayProvider().get()).isSameAs(BOUND_SHORT_ARRAY);
+ assertThat(basicComponent.getIntArrayProvider().get()).isSameAs(BOUND_INT_ARRAY);
+ assertThat(basicComponent.getLongArrayProvider().get()).isSameAs(BOUND_LONG_ARRAY);
+ assertThat(basicComponent.getBooleanArrayProvider().get()).isSameAs(BOUND_BOOLEAN_ARRAY);
+ assertThat(basicComponent.getFloatArrayProvider().get()).isSameAs(BOUND_FLOAT_ARRAY);
+ assertThat(basicComponent.getDoubleArrayProvider().get()).isSameAs(BOUND_DOUBLE_ARRAY);
+ }
+
+ @Theory public void noOpMembersInjection(BasicComponent basicComponent) {
+ Object object = new Object();
+ assertThat(basicComponent.noOpMembersInjection(object)).isSameAs(object);
+ }
+
+ @Theory public void basicObject_noDeps(BasicComponent basicComponent) {
+ assertThat(basicComponent.thing()).isNotNull();
+ }
+
+ @Theory public void inheritedMembersInjection(BasicComponent basicComponent) {
+ assertThat(basicComponent.typeWithInheritedMembersInjection().thing).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java b/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java
new file mode 100644
index 0000000..0310df6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/DependsOnGeneratedCodeTest.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class DependsOnGeneratedCodeTest {
+ @Test public void testComponentDependsOnGeneratedCode() {
+ assertThat(DaggerComponentDependsOnGeneratedCode.create().needsFactory()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java b/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java
new file mode 100644
index 0000000..f1c981f
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.sub.Exposed;
+import test.sub.PublicSubclass;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(JUnit4.class)
+public class GenericTest {
+
+ @Test public void testGenericComponentCreate() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component).isNotNull();
+ }
+
+ @Test public void testGenericSimpleReferences() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component.referencesGeneric().genericA.t).isNotNull();
+ }
+
+ @Test public void testGenericDoubleReferences() {
+ GenericComponent component = DaggerGenericComponent.create();
+ GenericDoubleReferences<A> doubleA = component.doubleGenericA();
+ assertThat(doubleA.a).isNotNull();
+ assertThat(doubleA.a2).isNotNull();
+ assertThat(doubleA.t).isNotNull();
+ assertThat(doubleA.t2).isNotNull();
+
+ GenericDoubleReferences<B> doubleB = component.doubleGenericB();
+ assertThat(doubleB.a).isNotNull();
+ assertThat(doubleB.a2).isNotNull();
+ assertThat(doubleB.t).isNotNull();
+ assertThat(doubleB.t2).isNotNull();
+ }
+
+ @Test public void complexGenerics() {
+ GenericComponent component = DaggerGenericComponent.create();
+ // validate these can be called w/o exceptions.
+ component.complexGenerics();
+ }
+
+ @Test public void noDepsGenerics() {
+ GenericComponent component = DaggerGenericComponent.create();
+ // validate these can be called w/o exceptions.
+ component.noDepsA();
+ component.noDepsB();
+ }
+
+ @Test public void boundedGenerics() {
+ BoundedGenericModule expected = new BoundedGenericModule();
+ BoundedGenericComponent component = DaggerBoundedGenericComponent.create();
+ BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
+ b1 = component.bounds1();
+ assertEquals(expected.provideInteger(), b1.a);
+ assertEquals(expected.provideArrayListString(), b1.b);
+ assertEquals(expected.provideLinkedListCharSeq(), b1.c);
+ assertEquals(expected.provideInteger(), b1.d);
+ assertEquals(expected.provideListOfInteger(), b1.e);
+
+ BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
+ b2 = component.bounds2();
+ assertEquals(expected.provideDouble(), b2.a);
+ assertEquals(expected.provideLinkedListString(), b2.b);
+ assertEquals(expected.provideArrayListOfComparableString(), b2.c);
+ assertEquals(expected.provideDouble(), b2.d);
+ assertEquals(expected.provideSetOfDouble(), b2.e);
+ }
+
+ @Test public void membersInjections() {
+ GenericComponent component = DaggerGenericComponent.create();
+ GenericChild<A> childA = new GenericChild<A>();
+ component.injectA(childA);
+ assertThat(childA.a).isNotNull();
+ assertThat(childA.b).isNotNull();
+ assertThat(childA.registeredA).isNotNull();
+ assertThat(childA.registeredB).isNotNull();
+ assertThat(childA.registeredT).isNotNull();
+ assertThat(childA.registeredX).isNotNull();
+ assertThat(childA.registeredY).isNotNull();
+
+ GenericChild<B> childB = new GenericChild<B>();
+ component.injectB(childB);
+ assertThat(childB.a).isNotNull();
+ assertThat(childB.b).isNotNull();
+ assertThat(childB.registeredA).isNotNull();
+ assertThat(childB.registeredB).isNotNull();
+ assertThat(childB.registeredT).isNotNull();
+ assertThat(childB.registeredX).isNotNull();
+ assertThat(childB.registeredY).isNotNull();
+ }
+
+ @Test public void packagePrivateTypeParameterDependencies() {
+ GenericComponent component = DaggerGenericComponent.create();
+ Exposed exposed = component.exposed();
+ assertThat(exposed.gpp.t).isNotNull();
+ assertThat(exposed.gpp2).isNotNull();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test public void publicSubclassWithPackagePrivateTypeParameterOfSuperclass() {
+ GenericComponent component = DaggerGenericComponent.create();
+ PublicSubclass publicSubclass = component.publicSubclass();
+ assertThat(((Generic)publicSubclass).t).isNotNull();
+ }
+
+ @Test public void singletonScopesAppliesToEachResolvedType() {
+ SingletonGenericComponent component = DaggerSingletonGenericComponent.create();
+ ScopedGeneric<A> a = component.scopedGenericA();
+ assertThat(a).isSameAs(component.scopedGenericA());
+ assertThat(a.t).isNotNull();
+
+ ScopedGeneric<B> b = component.scopedGenericB();
+ assertThat(b).isSameAs(component.scopedGenericB());
+ assertThat(b.t).isNotNull();
+
+ assertThat(a).isNotSameAs(b);
+ }
+
+ @Test public void genericModules() {
+ GenericComponent component = DaggerGenericComponent.create();
+ assertThat(component.iterableInt()).containsExactly(1, 2).inOrder();
+ assertThat(component.iterableDouble()).containsExactly(3d, 4d).inOrder();
+
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java b/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java
new file mode 100644
index 0000000..1b7e302
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package test;
+
+import com.google.auto.value.AutoAnnotation;
+import com.google.common.collect.ImmutableMap;
+import dagger.mapkeys.ClassKey;
+import dagger.mapkeys.StringKey;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Map;
+import javax.inject.Provider;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MultibindingTest {
+ private MultibindingComponent multibindingComponent;
+
+ @Before public void setUp() {
+ multibindingComponent = DaggerMultibindingComponent.builder()
+ .multibindingDependency(new MultibindingDependency() {
+ @Override public double doubleDependency() {
+ return 0.0;
+ }
+ })
+ .build();
+ }
+
+ @Test public void map() {
+ Map<String, String> map = multibindingComponent.map();
+ assertThat(map).hasSize(2);
+ assertThat(map).containsEntry("foo", "foo value");
+ assertThat(map).containsEntry("bar", "bar value");
+ }
+
+ @Test public void mapOfArrays() {
+ Map<String, String[]> map = multibindingComponent.mapOfArrays();
+ assertThat(map).hasSize(2);
+ assertThat(map).containsKey("foo");
+ assertThat(map.get("foo")).asList().containsExactly("foo1", "foo2").inOrder();
+ assertThat(map).containsKey("bar");
+ assertThat(map.get("bar")).asList().containsExactly("bar1", "bar2").inOrder();
+ }
+
+ @Test public void mapOfProviders() {
+ Map<String, Provider<String>> mapOfProviders = multibindingComponent.mapOfProviders();
+ assertThat(mapOfProviders).hasSize(2);
+ assertThat(mapOfProviders.get("foo").get()).isEqualTo("foo value");
+ assertThat(mapOfProviders.get("bar").get()).isEqualTo("bar value");
+ }
+
+ @Test public void mapKeysAndValues() {
+ assertThat(multibindingComponent.mapKeys()).containsExactly("foo", "bar");
+ assertThat(multibindingComponent.mapValues()).containsExactly("foo value", "bar value");
+ }
+
+ @Test public void nestedKeyMap() {
+ assertThat(multibindingComponent.nestedKeyMap()).isEqualTo(
+ ImmutableMap.of(
+ nestedWrappedKey(Integer.class), "integer",
+ nestedWrappedKey(Long.class), "long"));
+ }
+
+ @Test
+ public void unwrappedAnnotationKeyMap() {
+ assertThat(multibindingComponent.unwrappedAnnotationKeyMap())
+ .isEqualTo(ImmutableMap.of(testStringKey("foo\n"), "foo annotation"));
+ }
+
+ @Test
+ public void wrappedAnnotationKeyMap() {
+ @SuppressWarnings("unchecked")
+ Class<? extends Number>[] classes = new Class[] {Long.class, Integer.class};
+ assertThat(multibindingComponent.wrappedAnnotationKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ testWrappedAnnotationKey(
+ testStringKey("foo"), new int[] {1, 2, 3}, new ClassKey[] {}, classes),
+ "wrapped foo annotation"));
+ }
+
+ @Test
+ public void booleanKeyMap() {
+ assertThat(multibindingComponent.booleanKeyMap()).isEqualTo(ImmutableMap.of(true, "true"));
+ }
+
+ @Test
+ public void byteKeyMap() {
+ assertThat(multibindingComponent.byteKeyMap())
+ .isEqualTo(ImmutableMap.of((byte) 100, "100 byte"));
+ }
+
+ @Test
+ public void charKeyMap() {
+ assertThat(multibindingComponent.characterKeyMap())
+ .isEqualTo(ImmutableMap.of('a', "a char", '\n', "newline char"));
+ }
+
+ @Test
+ public void classKeyMap() {
+ assertThat(multibindingComponent.classKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ Integer.class, "integer",
+ Long.class, "long"));
+ }
+
+ @Test
+ public void numberClassKeyMap() {
+ assertThat(multibindingComponent.numberClassKeyMap())
+ .isEqualTo(
+ ImmutableMap.of(
+ BigDecimal.class, "bigdecimal",
+ BigInteger.class, "biginteger"));
+ }
+
+ @Test
+ public void intKeyMap() {
+ assertThat(multibindingComponent.integerKeyMap()).isEqualTo(ImmutableMap.of(100, "100 int"));
+ }
+
+ @Test
+ public void longKeyMap() {
+ assertThat(multibindingComponent.longKeyMap())
+ .isEqualTo(ImmutableMap.of((long) 100, "100 long"));
+ }
+
+ @Test
+ public void shortKeyMap() {
+ assertThat(multibindingComponent.shortKeyMap())
+ .isEqualTo(ImmutableMap.of((short) 100, "100 short"));
+ }
+
+ @Test public void setBindings() {
+ assertThat(multibindingComponent.set()).containsExactly(-90, -17, -1, 5, 6, 832, 1742);
+ }
+
+ @Test public void complexQualifierSet() {
+ assertThat(multibindingComponent.complexQualifierStringSet()).containsExactly("foo");
+ }
+
+ @AutoAnnotation
+ static StringKey testStringKey(String value) {
+ return new AutoAnnotation_MultibindingTest_testStringKey(value);
+ }
+
+ @AutoAnnotation
+ static NestedAnnotationContainer.NestedWrappedKey nestedWrappedKey(Class<?> value) {
+ return new AutoAnnotation_MultibindingTest_nestedWrappedKey(value);
+ }
+
+ @AutoAnnotation
+ static WrappedAnnotationKey testWrappedAnnotationKey(
+ StringKey value, int[] integers, ClassKey[] annotations, Class<? extends Number>[] classes) {
+ return new AutoAnnotation_MultibindingTest_testWrappedAnnotationKey(
+ value, integers, annotations, classes);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java b/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java
new file mode 100644
index 0000000..14c3e53
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/NestedTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class NestedTest {
+ @Test public void nestedFoo() {
+ OuterClassFoo.NestedComponent nestedFoo = DaggerOuterClassFoo_NestedComponent.create();
+ assertThat(nestedFoo.thing()).isNotNull();
+ }
+
+ @Test public void nestedBar() {
+ OuterClassBar.NestedComponent nestedBar = DaggerOuterClassBar_NestedComponent.create();
+ assertThat(nestedBar.injectedThing()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java b/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java
new file mode 100644
index 0000000..37d3f7a
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java
@@ -0,0 +1,34 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class NonComponentDependencyTest {
+ @Test public void testThing() {
+ NonComponentDependencyComponent component =
+ DaggerNonComponentDependencyComponent.builder()
+ .thingComponent(new NonComponentDependencyComponent.ThingComponentImpl())
+ .build();
+ assertThat(component).isNotNull();
+ assertThat(component.thingTwo()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java b/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java
new file mode 100644
index 0000000..46f5388
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/builder/BuilderTest.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.builder;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class BuilderTest {
+
+ @Test public void interfaceBuilder() {
+ TestComponentWithBuilderInterface.Builder builder =
+ DaggerTestComponentWithBuilderInterface.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
+ .stringModule(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithBuilderInterface component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void abstractClassBuilder() {
+ TestComponentWithBuilderAbstractClass.Builder builder =
+ TestComponentWithBuilderAbstractClass.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
+ .stringModule(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithBuilderAbstractClass component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void interfaceGenericBuilder() {
+ TestComponentWithGenericBuilderInterface.Builder builder =
+ DaggerTestComponentWithGenericBuilderInterface.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithGenericBuilderInterface component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void abstractClassGenericBuilder() {
+ TestComponentWithGenericBuilderAbstractClass.Builder builder =
+ DaggerTestComponentWithGenericBuilderAbstractClass.builder();
+
+ // Make sure things fail if we don't set our required modules.
+ try {
+ builder.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .depComponent(new DepComponent() {});
+ builder.doubleModule(new DoubleModule());
+ // Don't set other modules -- make sure it works.
+
+ TestComponentWithGenericBuilderAbstractClass component = builder.build();
+ assertThat(component.s()).isEqualTo("sam");
+ assertThat(component.i()).isEqualTo(1);
+ assertThat(component.d()).isWithin(0).of(4.2d);
+ assertThat(component.f()).isEqualTo(5.5f);
+ assertThat(component.l()).isEqualTo(6L);
+ }
+
+ @Test public void subcomponents_interface() {
+ ParentComponent parent = DaggerParentComponent.create();
+ TestChildComponentWithBuilderInterface.Builder builder1 = parent.childInterfaceBuilder();
+ try {
+ builder1.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder1.setM2(new IntModuleIncludingDoubleAndFloat(1))
+ .setM1(new StringModule("sam"))
+ .set(new ByteModule((byte)7));
+ builder1.set(new FloatModule());
+ TestChildComponentWithBuilderInterface child1 = builder1.build();
+ assertThat(child1.s()).isEqualTo("sam");
+ assertThat(child1.i()).isEqualTo(1);
+ assertThat(child1.d()).isWithin(0).of(4.2d);
+ assertThat(child1.f()).isEqualTo(5.5f);
+ assertThat(child1.l()).isEqualTo(6L);
+ assertThat(child1.b()).isEqualTo((byte)7);
+ }
+
+ @Test public void subcomponents_abstractclass() {
+ ParentComponent parent = DaggerParentComponent.create();
+ TestChildComponentWithBuilderAbstractClass.Builder builder2 =
+ parent.childAbstractClassBuilder();
+ try {
+ builder2.build();
+ fail();
+ } catch(IllegalStateException expected) {}
+
+ builder2.setM2(new IntModuleIncludingDoubleAndFloat(10))
+ .setM1(new StringModule("tara"))
+ .set(new ByteModule((byte)70));
+ builder2.set(new FloatModule());
+ TestChildComponentWithBuilderAbstractClass child2 = builder2.build();
+ assertThat(child2.s()).isEqualTo("tara");
+ assertThat(child2.i()).isEqualTo(10);
+ assertThat(child2.d()).isWithin(0).of(4.2d);
+ assertThat(child2.f()).isEqualTo(5.5f);
+ assertThat(child2.l()).isEqualTo(6L);
+ assertThat(child2.b()).isEqualTo((byte)70);
+ }
+
+ @Test
+ public void grandchildren() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle1 = parent.middleBuilder().set(new StringModule("sam")).build();
+ Grandchild grandchild1 =
+ middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ Grandchild grandchild2 =
+ middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
+
+ assertThat(middle1.s()).isEqualTo("sam");
+ assertThat(grandchild1.i()).isEqualTo(21);
+ assertThat(grandchild1.s()).isEqualTo("sam");
+ assertThat(grandchild2.i()).isEqualTo(22);
+ assertThat(grandchild2.s()).isEqualTo("sam");
+
+ // Make sure grandchildren from newer children have no relation to the older ones.
+ MiddleChild middle2 = parent.middleBuilder().set(new StringModule("tara")).build();
+ Grandchild grandchild3 =
+ middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(23)).build();
+ Grandchild grandchild4 =
+ middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(24)).build();
+
+ assertThat(middle2.s()).isEqualTo("tara");
+ assertThat(grandchild3.i()).isEqualTo(23);
+ assertThat(grandchild3.s()).isEqualTo("tara");
+ assertThat(grandchild4.i()).isEqualTo(24);
+ assertThat(grandchild4.s()).isEqualTo("tara");
+ }
+
+ @Test
+ public void diamondGrandchildren() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle = parent.middleBuilder().set(new StringModule("sam")).build();
+ OtherMiddleChild other = parent.otherBuilder().set(new StringModule("tara")).build();
+
+ Grandchild middlegrand =
+ middle.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ Grandchild othergrand =
+ other.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
+
+ assertThat(middle.s()).isEqualTo("sam");
+ assertThat(other.s()).isEqualTo("tara");
+ assertThat(middlegrand.s()).isEqualTo("sam");
+ assertThat(othergrand.s()).isEqualTo("tara");
+ assertThat(middlegrand.i()).isEqualTo(21);
+ assertThat(othergrand.i()).isEqualTo(22);
+ }
+
+ @Test
+ public void genericSubcomponentMethod() {
+ ParentOfGenericComponent parent =
+ DaggerParentOfGenericComponent.builder().stringModule(new StringModule("sam")).build();
+ Grandchild.Builder builder = parent.subcomponentBuilder();
+ Grandchild child = builder.set(new IntModuleIncludingDoubleAndFloat(21)).build();
+ assertThat(child.s()).isEqualTo("sam");
+ assertThat(child.i()).isEqualTo(21);
+ }
+
+ @Test
+ public void requireSubcomponentBuilderProviders() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle =
+ parent
+ .requiresMiddleChildBuilder()
+ .subcomponentBuilderProvider()
+ .get()
+ .set(new StringModule("sam"))
+ .build();
+ Grandchild grandchild =
+ middle
+ .requiresGrandchildBuilder()
+ .subcomponentBuilderProvider()
+ .get()
+ .set(new IntModuleIncludingDoubleAndFloat(12))
+ .build();
+ assertThat(middle.s()).isEqualTo("sam");
+ assertThat(grandchild.i()).isEqualTo(12);
+ assertThat(grandchild.s()).isEqualTo("sam");
+ }
+
+ @Test
+ public void requireSubcomponentBuilders() {
+ ParentComponent parent = DaggerParentComponent.create();
+ MiddleChild middle =
+ parent
+ .requiresMiddleChildBuilder()
+ .subcomponentBuilder()
+ .set(new StringModule("sam"))
+ .build();
+ Grandchild grandchild =
+ middle
+ .requiresGrandchildBuilder()
+ .subcomponentBuilder()
+ .set(new IntModuleIncludingDoubleAndFloat(12))
+ .build();
+ assertThat(middle.s()).isEqualTo("sam");
+ assertThat(grandchild.i()).isEqualTo(12);
+ assertThat(grandchild.s()).isEqualTo("sam");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java b/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java
new file mode 100644
index 0000000..d3bc2cb
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/cycle/CycleTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.cycle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.cycle.Cycles.A;
+import test.cycle.Cycles.C;
+import test.cycle.Cycles.ChildCycleComponent;
+import test.cycle.Cycles.CycleComponent;
+import test.cycle.Cycles.CycleMapComponent;
+import test.cycle.Cycles.S;
+import test.cycle.Cycles.SelfCycleComponent;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class CycleTest {
+ @Test
+ public void providerIndirectionSelfCycle() {
+ SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
+ S s = selfCycleComponent.s();
+ assertThat(s.sProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void providerIndirectionCycle() {
+ CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
+ A a = cycleComponent.a();
+ C c = cycleComponent.c();
+ assertThat(c.aProvider.get()).isNotNull();
+ assertThat(a.b.c.aProvider.get()).isNotNull();
+ assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void lazyIndirectionSelfCycle() {
+ SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
+ S s = selfCycleComponent.s();
+ assertThat(s.sLazy.get()).isNotNull();
+ }
+
+ @Test
+ public void lazyIndirectionCycle() {
+ CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
+ A a = cycleComponent.a();
+ C c = cycleComponent.c();
+ assertThat(c.aLazy.get()).isNotNull();
+ assertThat(a.b.c.aLazy.get()).isNotNull();
+ assertThat(a.e.d.b.c.aLazy.get()).isNotNull();
+ }
+
+ @Test
+ public void subcomponentIndirectionCycle() {
+ ChildCycleComponent childCycleComponent = DaggerCycles_CycleComponent.create().child();
+ A a = childCycleComponent.a();
+ assertThat(a.b.c.aProvider.get()).isNotNull();
+ assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
+ }
+
+ @Test
+ public void providerMapIndirectionCycle() {
+ CycleMapComponent cycleMapComponent = DaggerCycles_CycleMapComponent.create();
+ assertThat(cycleMapComponent.y()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX).containsKey("X");
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X")).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get().y).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfX).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY).containsKey("Y");
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y")).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get()).isNotNull();
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfX).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfY).hasSize(1);
+ assertThat(cycleMapComponent.y().mapOfProvidersOfY).hasSize(1);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java b/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java
new file mode 100644
index 0000000..e50eaee
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/cycle/LongCycleTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.cycle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.cycle.LongCycle.LongCycleComponent;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class LongCycleTest {
+
+ /**
+ * Tests a cycle long enough that the real factory is created in a separate initialize method from
+ * the delegate factory.
+ */
+ @Test
+ public void longCycle() {
+ LongCycleComponent longCycleComponent = DaggerLongCycle_LongCycleComponent.create();
+ assertThat(longCycleComponent.class1()).isNotNull();
+ }
+
+ /**
+ * Fails if {@link LongCycleComponent} doesn't have a long enough cycle to make sure the real
+ * factory is created in a separate method from the delegate factory.
+ */
+ @Test
+ public void longCycleHasMoreThanOneInitializeMethod() throws NoSuchMethodException {
+ DaggerLongCycle_LongCycleComponent.class
+ .getDeclaredMethod("initialize1", DaggerLongCycle_LongCycleComponent.Builder.class);
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java b/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java
new file mode 100644
index 0000000..411ecb1
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.membersinject;
+
+import dagger.MembersInjector;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import test.multipackage.DaggerMembersInjectionVisibilityComponent;
+import test.multipackage.MembersInjectionVisibilityComponent;
+import test.multipackage.a.AGrandchild;
+import test.multipackage.a.AParent;
+import test.multipackage.b.BChild;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MembersInjectTest {
+ @Test public void testMembersInject_arrays() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfStringArray childOfStringArray = new ChildOfStringArray();
+ component.inject(childOfStringArray);
+ }
+
+ @Test public void testMembersInject_nestedArrays() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfArrayOfParentOfStringArray childOfArrayOfParentOfStringArray =
+ new ChildOfArrayOfParentOfStringArray();
+ component.inject(childOfArrayOfParentOfStringArray);
+ }
+
+ @Test public void testMembersInject_primitives() {
+ MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
+
+ ChildOfPrimitiveIntArray childOfPrimitiveIntArray = new ChildOfPrimitiveIntArray();
+ component.inject(childOfPrimitiveIntArray);
+ }
+
+ @Test
+ public void testMembersInject_overrides() {
+ MembersInjectionVisibilityComponent component =
+ DaggerMembersInjectionVisibilityComponent.create();
+ AParent aParent = new AParent();
+ component.inject(aParent);
+ assertThat(aParent.aParentField()).isNotNull();
+ assertThat(aParent.aParentMethod()).isNotNull();
+
+ BChild aChild = new BChild();
+ component.inject(aChild);
+ assertThat(aChild.aParentField()).isNotNull();
+ assertThat(aChild.aParentMethod()).isNull();
+ assertThat(aChild.aChildField()).isNotNull();
+ assertThat(aChild.aChildMethod()).isNotNull();
+
+ AGrandchild aGrandchild = new AGrandchild();
+ component.inject(aGrandchild);
+ assertThat(aGrandchild.aParentField()).isNotNull();
+ assertThat(aGrandchild.aParentMethod()).isNotNull();
+ assertThat(aGrandchild.aChildField()).isNotNull();
+ assertThat(aGrandchild.aChildMethod()).isNull();
+ assertThat(aGrandchild.aGrandchildField()).isNotNull();
+ assertThat(aGrandchild.aGrandchildMethod()).isNotNull();
+ }
+
+ @Test
+ public void testNonRequestedMembersInjector() {
+ NonRequestedChild child = new NonRequestedChild();
+ Provider<String> provider =
+ new Provider<String>() {
+ @Override
+ public String get() {
+ return "field!";
+ }
+ };
+ MembersInjector<NonRequestedChild> injector = new NonRequestedChild_MembersInjector(provider);
+ injector.injectMembers(child);
+ assertThat(child.t).isEqualTo("field!");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java b/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java
new file mode 100644
index 0000000..a0e1e22
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/nullables/NullabilityTest.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package test.nullables;
+
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class NullabilityTest {
+ @Test public void testNullability_provides() {
+ NullModule module = new NullModule();
+ NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
+
+ // Can't construct NullFoo because it depends on Number, and Number was null.
+ try {
+ component.nullFoo();
+ fail();
+ } catch (NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable @Provides method");
+ }
+
+ // set number to non-null so we can create
+ module.numberValue = 1;
+ NullFoo nullFoo = component.nullFoo();
+
+ // Then set it back to null so we can test its providers.
+ module.numberValue = null;
+ validate(true, nullFoo.string, nullFoo.stringProvider, nullFoo.numberProvider);
+ validate(true, nullFoo.methodInjectedString, nullFoo.methodInjectedStringProvider,
+ nullFoo.methodInjectedNumberProvider);
+ validate(true, nullFoo.fieldInjectedString, nullFoo.fieldInjectedStringProvider,
+ nullFoo.fieldInjectedNumberProvider);
+ }
+
+ @Test public void testNullability_components() {
+ NullComponent nullComponent = new NullComponent() {
+ @Override public Provider<String> stringProvider() {
+ return new Provider<String>() {
+ @Override public String get() {
+ return null;
+ }
+ };
+ }
+
+ @Override public String string() {
+ return null;
+ }
+
+ @Override public Provider<Number> numberProvider() {
+ return new Provider<Number>() {
+ @Override public Number get() {
+ return null;
+ }
+ };
+ }
+
+ @Override public Number number() {
+ return null;
+ }
+
+ @Override public NullFoo nullFoo() {
+ return null;
+ }
+ };
+ NullComponentWithDependency component =
+ DaggerNullComponentWithDependency.builder().nullComponent(nullComponent).build();
+ validate(false, component.string(), component.stringProvider(), component.numberProvider());
+
+ // Also validate that the component's number() method fails
+ try {
+ component.number();
+ fail();
+ } catch (NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable component method");
+ }
+ }
+
+ private void validate(boolean fromProvides,
+ String string,
+ Provider<String> stringProvider,
+ Provider<Number> numberProvider) {
+ assertThat(string).isNull();
+ assertThat(numberProvider).isNotNull();
+ try {
+ numberProvider.get();
+ fail();
+ } catch(NullPointerException npe) {
+ assertThat(npe).hasMessage("Cannot return null from a non-@Nullable "
+ + (fromProvides ? "@Provides" : "component") + " method");
+ }
+ assertThat(stringProvider.get()).isNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java b/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java
new file mode 100644
index 0000000..3972594
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/staticprovides/StaticProvidesTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.staticprovides;
+
+import com.google.common.collect.ImmutableSet;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+@RunWith(Parameterized.class)
+public class StaticProvidesTest {
+ @Parameters
+ public static Collection<Object[]> components() {
+ return Arrays.asList(new Object[][] {
+ {DaggerStaticTestComponent.create()},
+ {DaggerStaticTestComponentWithBuilder.builder().build()},
+ {DaggerStaticTestComponentWithBuilder.builder()
+ .allStaticModule(new AllStaticModule())
+ .someStaticModule(new SomeStaticModule())
+ .build()}});
+ }
+
+ @Parameter
+ public StaticTestComponent component;
+
+ @Test public void setMultibinding() {
+ assertThat(component.getMultiboundStrings()).isEqualTo(ImmutableSet.of(
+ AllStaticModule.class + ".contributeString",
+ SomeStaticModule.class + ".contributeStringFromAStaticMethod",
+ SomeStaticModule.class + ".contributeStringFromAnInstanceMethod"));
+ }
+
+ @Test public void allStaticProvidesModules_noFieldInComponentBuilder() {
+ for (Field field : DaggerStaticTestComponent.Builder.class.getDeclaredFields()) {
+ assertWithMessage(field.getName())
+ .that(field.getType()).isNotEqualTo(AllStaticModule.class);
+ }
+ }
+
+ @Test public void allStaticProvidesModules_deprecatedMethodInComponentBuilder() {
+ for (Method method : DaggerStaticTestComponent.Builder.class.getDeclaredMethods()) {
+ if (Arrays.asList(method.getParameterTypes()).contains(AllStaticModule.class)) {
+ assertWithMessage(method.getName())
+ .that(method.isAnnotationPresent(Deprecated.class))
+ .isTrue();
+ }
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java
new file mode 100644
index 0000000..f57a778
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentMultibindingsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+@RunWith(Parameterized.class)
+public class SubcomponentMultibindingsTest {
+
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> parameters() {
+ return ImmutableList.of(
+ new Object[] {DaggerParentComponentWithMultibindings.create()},
+ new Object[] {DaggerParentComponentWithoutMultibindings.create()});
+ }
+
+ private ParentComponentWithoutMultibindings parent;
+
+ public SubcomponentMultibindingsTest(ParentComponentWithoutMultibindings parentComponent) {
+ this.parent = parentComponent;
+ }
+
+ @Test
+ public void testMultibindingsInSubcomponents() {
+ RequiresMultibindingsInChild requiresMultibindingsInChild =
+ parent.childComponent().requiresMultibindingsInChild();
+
+ assertWithMessage("requiresMultiboundObjects.setOfObjects")
+ .that(requiresMultibindingsInChild.requiresMultiboundObjects().setOfObjects())
+ .containsExactly("object provided by parent", "object provided by child");
+
+ assertWithMessage("requiresMultiboundObjects.mapOfObjects")
+ .that(requiresMultibindingsInChild.requiresMultiboundObjects().mapOfObjects())
+ .isEqualTo(
+ ImmutableMap.of("parent key", "object in parent", "child key", "object in child"));
+
+ assertWithMessage("requiresMultiboundStrings")
+ .that(requiresMultibindingsInChild.requiresMultiboundStrings().setOfStrings())
+ .containsExactly("string provided by parent");
+
+ assertWithMessage("requiresMultiboundStrings.mapOfStrings")
+ .that(requiresMultibindingsInChild.requiresMultiboundStrings().mapOfStrings())
+ .isEqualTo(ImmutableMap.of("parent key", "string in parent"));
+ }
+
+ @Test
+ public void testOverriddenMultibindingsInSubcomponents() {
+ RequiresMultibindingsInChild requiresMultibindingsInChild =
+ parent.childComponent().requiresMultibindingsInChild();
+
+ assertWithMessage("setOfRequiresMultiboundObjects")
+ .that(requiresMultibindingsInChild.setOfRequiresMultiboundObjects())
+ .hasSize(1);
+
+ RequiresMultiboundObjects onlyElementInMultiboundRequiresMultiboundObjects =
+ getOnlyElement(requiresMultibindingsInChild.setOfRequiresMultiboundObjects());
+
+ assertWithMessage("setOfRequiresMultiboundObjects[only].setOfObjects")
+ .that(onlyElementInMultiboundRequiresMultiboundObjects.setOfObjects())
+ .containsExactly("object provided by parent", "object provided by child");
+
+ assertWithMessage("setOfRequiresMultiboundObjects[only].mapOfObjects")
+ .that(onlyElementInMultiboundRequiresMultiboundObjects.mapOfObjects())
+ .isEqualTo(
+ ImmutableMap.of("parent key", "object in parent", "child key", "object in child"));
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java
new file mode 100644
index 0000000..cb62925
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.google.common.collect.Sets.intersection;
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(Parameterized.class)
+public class SubcomponentTest {
+ private static final ParentComponent parentComponent = DaggerParentComponent.create();
+ private static final ParentOfGenericComponent parentOfGenericComponent =
+ DaggerParentOfGenericComponent.create();
+
+ @Parameters
+ public static Collection<Object[]> parameters() {
+ return Arrays.asList(new Object[][] {
+ { parentComponent, parentComponent.newChildComponent() },
+ { parentComponent, parentComponent.newChildAbstractClassComponent() },
+ { parentOfGenericComponent, parentOfGenericComponent.subcomponent() }});
+ }
+
+ private final ParentGetters parentGetters;
+ private final ChildComponent childComponent;
+
+ public SubcomponentTest(ParentGetters parentGetters, ChildComponent childComponent) {
+ this.parentGetters = parentGetters;
+ this.childComponent = childComponent;
+ }
+
+
+ @Test
+ public void scopePropagatesUpward_class() {
+ assertThat(childComponent.requiresSingleton().singletonType())
+ .isSameAs(childComponent.requiresSingleton().singletonType());
+ assertThat(childComponent.requiresSingleton().singletonType())
+ .isSameAs(childComponent.newGrandchildComponent().requiresSingleton().singletonType());
+ }
+
+ @Test
+ public void scopePropagatesUpward_provides() {
+ assertThat(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton())
+ .isSameAs(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton());
+ assertThat(childComponent
+ .requiresSingleton().unscopedTypeBoundAsSingleton())
+ .isSameAs(childComponent.newGrandchildComponent()
+ .requiresSingleton().unscopedTypeBoundAsSingleton());
+ }
+
+ @Test
+ public void multibindingContributions() {
+ Set<Object> parentObjectSet = parentGetters.objectSet();
+ assertThat(parentObjectSet).hasSize(2);
+ Set<Object> childObjectSet = childComponent.objectSet();
+ assertThat(childObjectSet).hasSize(3);
+ Set<Object> grandchildObjectSet =
+ childComponent.newGrandchildComponent().objectSet();
+ assertThat(grandchildObjectSet).hasSize(4);
+ assertThat(intersection(parentObjectSet, childObjectSet)).hasSize(1);
+ assertThat(intersection(parentObjectSet, grandchildObjectSet)).hasSize(1);
+ assertThat(intersection(childObjectSet, grandchildObjectSet)).hasSize(1);
+ }
+
+ @Test
+ public void unscopedProviders() {
+ assertThat(parentGetters.getUnscopedTypeProvider())
+ .isSameAs(childComponent.getUnscopedTypeProvider());
+ assertThat(parentGetters.getUnscopedTypeProvider())
+ .isSameAs(childComponent
+ .newGrandchildComponent()
+ .getUnscopedTypeProvider());
+ }
+
+ @Test
+ public void passedModules() {
+ ChildModuleWithState childModuleWithState = new ChildModuleWithState();
+ ChildComponentRequiringModules childComponent1 =
+ parentComponent.newChildComponentRequiringModules(
+ new ChildModuleWithParameters(new Object()),
+ childModuleWithState);
+ ChildComponentRequiringModules childComponent2 =
+ parentComponent.newChildComponentRequiringModules(
+ new ChildModuleWithParameters(new Object()),
+ childModuleWithState);
+ assertThat(childComponent1.getInt()).isEqualTo(0);
+ assertThat(childComponent2.getInt()).isEqualTo(1);
+ }
+
+ @Test
+ public void dependenceisInASubcomponent() {
+ assertThat(childComponent.newGrandchildComponent().needsAnInterface()).isNotNull();
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java
new file mode 100644
index 0000000..27dcbb6
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/hiding/SubcomponentHidingTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.hiding;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class SubcomponentHidingTest {
+ @Test public void moduleNameHiding() {
+ ParentComponent parent = DaggerParentComponent.create();
+ assertThat(parent.aCommonName().toString()).isEqualTo("a");
+ assertThat(parent.newChildComponent().aCommonName().toString()).isEqualTo("a");
+ assertThat(parent.newChildComponent().bCommonName().toString()).isEqualTo("1");
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java
new file mode 100644
index 0000000..7e92371
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/repeat/RepeatedModuleTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.subcomponent.repeat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public final class RepeatedModuleTest {
+ private ParentComponent parentComponent;
+
+ @Before
+ public void initializeParentComponent() {
+ this.parentComponent = DaggerParentComponent.builder().build();
+ }
+
+ @Test
+ public void repeatedModuleHasSameStateInSubcomponent() {
+ SubcomponentWithRepeatedModule childComponent =
+ parentComponent.newChildComponentBuilder().build();
+ assertThat(parentComponent.state()).isSameAs(childComponent.state());
+ }
+
+ @Test
+ public void repeatedModuleHasSameStateInGrandchildSubcomponent() {
+ SubcomponentWithoutRepeatedModule childComponent =
+ parentComponent.newChildComponentWithoutRepeatedModule();
+ SubcomponentWithRepeatedModule grandchildComponent =
+ childComponent.newGrandchildBuilder().build();
+ assertThat(parentComponent.state()).isSameAs(grandchildComponent.state());
+ }
+
+ @Test
+ public void repeatedModuleBuilderThrowsInSubcomponent() {
+ SubcomponentWithRepeatedModule.Builder childComponentBuilder =
+ parentComponent.newChildComponentBuilder();
+ try {
+ childComponentBuilder.repeatedModule(new RepeatedModule());
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessage(
+ "test.subcomponent.repeat.RepeatedModule cannot be set "
+ + "because it is inherited from the enclosing component");
+ }
+ }
+
+ @Test
+ public void repeatedModuleBuilderThrowsInGrandchildSubcomponent() {
+ SubcomponentWithoutRepeatedModule childComponent =
+ parentComponent.newChildComponentWithoutRepeatedModule();
+ SubcomponentWithRepeatedModule.Builder grandchildComponentBuilder =
+ childComponent.newGrandchildBuilder();
+ try {
+ grandchildComponentBuilder.repeatedModule(new RepeatedModule());
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ assertThat(expected)
+ .hasMessage(
+ "test.subcomponent.repeat.RepeatedModule cannot be set "
+ + "because it is inherited from the enclosing component");
+ }
+ }
+}
diff --git a/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java b/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java
new file mode 100644
index 0000000..d79b06b
--- /dev/null
+++ b/compiler/src/it/functional-tests/src/test/java/test/tck/TckTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package test.tck;
+
+import junit.framework.Test;
+import org.atinject.tck.Tck;
+import org.atinject.tck.auto.Car;
+import org.atinject.tck.auto.Convertible;
+
+/**
+ * Test suite to execute the JSR-330 TCK in JUnit.
+ */
+public class TckTest {
+ public static Test suite() {
+ CarShop carShopComponent = DaggerCarShop.create();
+ Car car = carShopComponent.make();
+ Convertible.localConvertible.set((Convertible) car);
+ return Tck.testsFor(car, false, false);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/pom.xml b/compiler/src/it/producers-functional-tests/pom.xml
new file mode 100644
index 0000000..a0d1649
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 Google, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+ <groupId>dagger.tests</groupId>
+ <artifactId>producers-functional-tests</artifactId>
+ <name>Producers Functional Tests</name>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-producers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>../../../../checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedComponent.java
new file mode 100644
index 0000000..a80ea49
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedComponent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Component;
+
+@Component(modules = DependedModule.class)
+interface DependedComponent {
+ String getGreeting();
+}
+
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedModule.java
new file mode 100644
index 0000000..dc62612
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class DependedModule {
+ @Provides
+ String provideGreeting() {
+ return "Hello world!";
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProducerModule.java
new file mode 100644
index 0000000..fe47c99
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProducerModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+import java.util.List;
+
+@ProducerModule
+final class DependedProducerModule {
+
+ @Produces
+ int produceNumberOfGreetings() {
+ return 2;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProductionComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProductionComponent.java
new file mode 100644
index 0000000..ba98e36
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependedProductionComponent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+@ProductionComponent(modules = DependedProducerModule.class)
+interface DependedProductionComponent {
+ ListenableFuture<Integer> numGreetings();
+}
+
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentComponent.java
new file mode 100644
index 0000000..85709f0
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentComponent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+import java.util.List;
+
+@ProductionComponent(
+ modules = DependentProducerModule.class,
+ dependencies = {DependedComponent.class, DependedProductionComponent.class})
+interface DependentComponent {
+ ListenableFuture<List<String>> greetings();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentProducerModule.java
new file mode 100644
index 0000000..e16c822
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/DependentProducerModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+import java.util.List;
+
+@ProducerModule
+final class DependentProducerModule {
+ @Produces
+ ListenableFuture<List<String>> greetings(Integer numGreetings, String greeting) {
+ List<String> greetings = ImmutableList.of(
+ String.valueOf(numGreetings), greeting, Ascii.toUpperCase(greeting));
+ return Futures.immediateFuture(greetings);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingComponent.java
new file mode 100644
index 0000000..6277e62
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingComponent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Produced;
+import dagger.producers.ProductionComponent;
+import java.util.Set;
+import producerstest.MultibindingProducerModule.PossiblyThrowingSet;
+
+@ProductionComponent(modules = MultibindingProducerModule.class)
+interface MultibindingComponent {
+ ListenableFuture<Set<String>> strs();
+ ListenableFuture<Integer> strCount();
+
+ ListenableFuture<Set<Produced<String>>> successfulSet();
+
+ @PossiblyThrowingSet
+ ListenableFuture<Set<Produced<String>>> possiblyThrowingSet();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingProducerModule.java
new file mode 100644
index 0000000..09cd5bd
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/MultibindingProducerModule.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+import javax.inject.Qualifier;
+
+import static dagger.producers.Produces.Type.SET;
+import static dagger.producers.Produces.Type.SET_VALUES;
+
+@ProducerModule
+final class MultibindingProducerModule {
+ @Qualifier
+ @interface PossiblyThrowingSet {}
+
+ @Produces(type = SET)
+ static ListenableFuture<String> futureStr() {
+ return Futures.immediateFuture("foo");
+ }
+
+ @Produces(type = SET)
+ static String str() {
+ return "bar";
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> futureStrs() {
+ return Futures.<Set<String>>immediateFuture(ImmutableSet.of("foo1", "foo2"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> strs() {
+ return ImmutableSet.of("bar1", "bar2");
+ }
+
+ @Produces
+ static int strCount(Set<String> strs) {
+ return strs.size();
+ }
+
+ @Produces(type = SET)
+ @PossiblyThrowingSet
+ static String successfulStringForSet() {
+ return "singleton";
+ }
+
+ @Produces(type = SET_VALUES)
+ @PossiblyThrowingSet
+ static Set<String> successfulStringsForSet() {
+ return ImmutableSet.of("double", "ton");
+ }
+
+ @Produces(type = SET)
+ @PossiblyThrowingSet
+ static String throwingStringForSet() {
+ throw new RuntimeException("monkey");
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Request.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Request.java
new file mode 100644
index 0000000..0227be6
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Request.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import javax.inject.Inject;
+
+final class Request {
+ private final String name;
+
+ @Inject
+ Request() {
+ this.name = "Request";
+ }
+
+ String name() {
+ return this.name;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Response.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Response.java
new file mode 100644
index 0000000..8618ff5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/Response.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+final class Response {
+ private final String data;
+
+ Response(String data) {
+ this.data = data;
+ }
+
+ String data() {
+ return this.data;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseModule.java
new file mode 100644
index 0000000..1edbe8a
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class ResponseModule {
+ @Provides
+ static int requestNumber() {
+ return 5;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseProducerModule.java
new file mode 100644
index 0000000..0ef2ae8
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/ResponseProducerModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+@ProducerModule(includes = ResponseModule.class)
+final class ResponseProducerModule {
+ @Produces
+ static ListenableFuture<String> greeting() {
+ return Futures.immediateFuture("Hello");
+ }
+
+ @Produces
+ static Response response(String greeting, Request request, int requestNumber) {
+ return new Response(String.format("%s, %s #%d!", greeting, request.name(), requestNumber));
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleComponent.java
new file mode 100644
index 0000000..1d1e492
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+@ProductionComponent(modules = ResponseProducerModule.class)
+interface SimpleComponent {
+ ListenableFuture<Response> response();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleProducerModule.java
new file mode 100644
index 0000000..2d831ed
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/SimpleProducerModule.java
@@ -0,0 +1,219 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.io.IOException;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+
+import static dagger.producers.Produces.Type.SET;
+import static dagger.producers.Produces.Type.SET_VALUES;
+
+/**
+ * A module that contains various signatures of produces methods. This is not used in any
+ * components.
+ */
+@ProducerModule
+final class SimpleProducerModule {
+ @Qualifier @interface Qual {
+ int value();
+ }
+
+ // Unique bindings.
+
+ @Produces
+ @Qual(-2)
+ static ListenableFuture<String> throwingProducer() {
+ throw new RuntimeException("monkey");
+ }
+
+ @Produces
+ @Qual(-1)
+ static ListenableFuture<String> settableFutureStr(SettableFuture<String> future) {
+ return future;
+ }
+
+ @Produces
+ @Qual(0)
+ static String str() {
+ return "str";
+ }
+
+ @Produces
+ @Qual(1)
+ static ListenableFuture<String> futureStr() {
+ return Futures.immediateFuture("future str");
+ }
+
+ @Produces
+ @Qual(2)
+ static String strWithArg(int i) {
+ return "str with arg";
+ }
+
+ @Produces
+ @Qual(3)
+ static ListenableFuture<String> futureStrWithArg(int i) {
+ return Futures.immediateFuture("future str with arg");
+ }
+
+ @Produces
+ @Qual(4)
+ static String strThrowingException() throws IOException {
+ return "str throwing exception";
+ }
+
+ @Produces
+ @Qual(5)
+ static ListenableFuture<String> futureStrThrowingException() throws IOException {
+ return Futures.immediateFuture("future str throwing exception");
+ }
+
+ @Produces
+ @Qual(6)
+ static String strWithArgThrowingException(int i) throws IOException {
+ return "str with arg throwing exception";
+ }
+
+ @Produces
+ @Qual(7)
+ static ListenableFuture<String> futureStrWithArgThrowingException(int i) throws IOException {
+ return Futures.immediateFuture("future str with arg throwing exception");
+ }
+
+ @Produces
+ @Qual(8)
+ static String strWithArgs(int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) {
+ return "str with args";
+ }
+
+ @Produces
+ @Qual(9)
+ static String strWithArgsThrowingException(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
+ return "str with args throwing exception";
+ }
+
+ @Produces
+ @Qual(10)
+ static ListenableFuture<String> futureStrWithArgs(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) {
+ return Futures.immediateFuture("future str with args");
+ }
+
+ @Produces
+ @Qual(11)
+ static ListenableFuture<String> futureStrWithArgsThrowingException(
+ int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
+ return Futures.immediateFuture("str with args throwing exception");
+ }
+
+ // Set bindings.
+
+ @Produces(type = SET)
+ static String setOfStrElement() {
+ return "set of str element";
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementThrowingException() throws IOException {
+ return "set of str element throwing exception";
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElement() {
+ return Futures.immediateFuture("set of str element");
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementThrowingException() throws IOException {
+ return Futures.immediateFuture("set of str element throwing exception");
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementWithArg(int i) {
+ return "set of str element with arg";
+ }
+
+ @Produces(type = SET)
+ static String setOfStrElementWithArgThrowingException(int i) throws IOException {
+ return "set of str element with arg throwing exception";
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementWithArg(int i) {
+ return Futures.immediateFuture("set of str element with arg");
+ }
+
+ @Produces(type = SET)
+ static ListenableFuture<String> setOfStrFutureElementWithArgThrowingException(int i)
+ throws IOException {
+ return Futures.immediateFuture("set of str element with arg throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValues() {
+ return ImmutableSet.of("set of str 1", "set of str 2");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesThrowingException() throws IOException {
+ return ImmutableSet.of("set of str 1", "set of str 2 throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValues() {
+ return Futures.<Set<String>>immediateFuture(ImmutableSet.of("set of str 1", "set of str 2"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesThrowingException() throws IOException {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str 1", "set of str 2 throwing exception"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesWithArg(int i) {
+ return ImmutableSet.of("set of str with arg 1", "set of str with arg 2");
+ }
+
+ @Produces(type = SET_VALUES)
+ static Set<String> setOfStrValuesWithArgThrowingException(int i) throws IOException {
+ return ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception");
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesWithArg(int i) {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str with arg 1", "set of str with arg 2"));
+ }
+
+ @Produces(type = SET_VALUES)
+ static ListenableFuture<Set<String>> setOfStrFutureValuesWithArgThrowingException(int i)
+ throws IOException {
+ return Futures.<Set<String>>immediateFuture(
+ ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception"));
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/ComponentDependency.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/ComponentDependency.java
new file mode 100644
index 0000000..7bba4ea
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/ComponentDependency.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.badexecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+interface ComponentDependency {
+ ListenableFuture<Double> doubleDep();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleComponent.java
new file mode 100644
index 0000000..6b3536e
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleComponent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.badexecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+/**
+ * A component that contains entry points that exercise different execution paths, for verifying the
+ * behavior when the executor throws a {@link java.util.concurrent.RejectedExecutionException}.
+ */
+@ProductionComponent(dependencies = ComponentDependency.class, modules = SimpleProducerModule.class)
+interface SimpleComponent {
+ /** An entry point exposing a producer method with no args. */
+ ListenableFuture<String> noArgStr();
+
+ /** An entry point exposing a producer method that depends on another producer method. */
+ ListenableFuture<Integer> singleArgInt();
+
+ /** An entry point exposing a producer method that depends on a component dependency method. */
+ ListenableFuture<Boolean> singleArgBool();
+
+ /** An entry point exposing a component dependency method. */
+ ListenableFuture<Double> doubleDep();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleProducerModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleProducerModule.java
new file mode 100644
index 0000000..00ab037
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/badexecutor/SimpleProducerModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.badexecutor;
+
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+@ProducerModule
+final class SimpleProducerModule {
+ @Produces
+ static String noArgStr() {
+ return "no arg string";
+ }
+
+ @Produces
+ static int singleArgInt(String arg) {
+ return arg.length();
+ }
+
+ @Produces
+ static boolean singleArgBool(double arg) {
+ return arg > 0.0;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/DepComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/DepComponent.java
new file mode 100644
index 0000000..dadde7b
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/DepComponent.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.builder;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+interface DepComponent {
+ ListenableFuture<Double> d();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/IntModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/IntModule.java
new file mode 100644
index 0000000..7f99836
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/IntModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.builder;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class IntModule {
+ @Provides
+ static int i() {
+ return 42;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/StringModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/StringModule.java
new file mode 100644
index 0000000..cdf0793
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/StringModule.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.builder;
+
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+
+@ProducerModule
+final class StringModule {
+ @Produces
+ static String str(int i) {
+ return "arg: " + i;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/TestComponentWithBuilder.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/TestComponentWithBuilder.java
new file mode 100644
index 0000000..16dc9ba
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/builder/TestComponentWithBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.builder;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+import java.util.concurrent.Executor;
+
+@ProductionComponent(
+ modules = {StringModule.class, IntModule.class},
+ dependencies = DepComponent.class
+)
+interface TestComponentWithBuilder {
+ ListenableFuture<String> s();
+ ListenableFuture<Double> d();
+
+ @ProductionComponent.Builder
+ interface Builder {
+ Builder depComponent(DepComponent depComponent);
+ Builder strModule(StringModule strModule);
+ Builder executor(Executor executor);
+ TestComponentWithBuilder build();
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoredComponent.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoredComponent.java
new file mode 100644
index 0000000..48acbab
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoredComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProductionComponent;
+
+@ProductionComponent(modules = {MonitoringModule.class, StubModule.class, ServingModule.class})
+interface MonitoredComponent {
+ ListenableFuture<String> output();
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoringModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoringModule.java
new file mode 100644
index 0000000..0c42090
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/MonitoringModule.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+
+import static dagger.Provides.Type.SET;
+
+@Module
+final class MonitoringModule {
+ private final ProductionComponentMonitor.Factory monitorFactory;
+
+ MonitoringModule(ProductionComponentMonitor.Factory monitorFactory) {
+ this.monitorFactory = monitorFactory;
+ }
+
+ @Provides(type = SET)
+ ProductionComponentMonitor.Factory monitorFactory() {
+ return monitorFactory;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/ServingModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/ServingModule.java
new file mode 100644
index 0000000..d5bec22
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/ServingModule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import javax.inject.Qualifier;
+import producerstest.monitoring.StubModule.ForServer1;
+import producerstest.monitoring.StubModule.ForServer2;
+
+@ProducerModule
+final class ServingModule {
+ @Qualifier
+ @interface RequestData {}
+
+ @Qualifier
+ @interface IntermediateData {}
+
+ @Produces
+ @RequestData
+ static String requestData() {
+ return "Hello, World!";
+ }
+
+ @Produces
+ @IntermediateData
+ static ListenableFuture<String> callServer1(
+ @RequestData String data, @ForServer1 StringStub stub) {
+ return stub.run(data);
+ }
+
+ @Produces
+ static ListenableFuture<String> callServer2(
+ @IntermediateData String data, @ForServer2 StringStub stub) {
+ return stub.run(data);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StringStub.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StringStub.java
new file mode 100644
index 0000000..195dd28
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StringStub.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+interface StringStub {
+ ListenableFuture<String> run(String input);
+}
diff --git a/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StubModule.java b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StubModule.java
new file mode 100644
index 0000000..dc8ab62
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/main/java/producerstest/monitoring/StubModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Qualifier;
+
+@Module
+final class StubModule {
+ @Qualifier
+ @interface ForServer1 {}
+
+ @Qualifier
+ @interface ForServer2 {}
+
+ private final StringStub server1;
+ private final StringStub server2;
+
+ StubModule(StringStub server1, StringStub server2) {
+ this.server1 = server1;
+ this.server2 = server2;
+ }
+
+ @Provides
+ @ForServer1
+ StringStub server1() {
+ return server1;
+ }
+
+ @Provides
+ @ForServer2
+ StringStub server2() {
+ return server2;
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/DependentTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/DependentTest.java
new file mode 100644
index 0000000..b2533d7
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/DependentTest.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class DependentTest {
+ @Test public void dependentComponent() throws Exception {
+ DependentComponent dependentComponent = DaggerDependentComponent
+ .builder()
+ .dependedProductionComponent(DaggerDependedProductionComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .build())
+ .dependedComponent(DaggerDependedComponent.create())
+ .executor(MoreExecutors.directExecutor())
+ .build();
+ assertThat(dependentComponent).isNotNull();
+ assertThat(dependentComponent.greetings().get()).containsExactly(
+ "2", "Hello world!", "HELLO WORLD!");
+ }
+
+ @Test public void reuseBuilderWithDependentComponent() throws Exception {
+ DaggerDependentComponent.Builder dependentComponentBuilder = DaggerDependentComponent
+ .builder()
+ .executor(MoreExecutors.directExecutor());
+
+ DependentComponent componentUsingComponents = dependentComponentBuilder
+ .dependedProductionComponent(DaggerDependedProductionComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .build())
+ .dependedComponent(DaggerDependedComponent.create())
+ .build();
+
+ DependentComponent componentUsingJavaImpls = dependentComponentBuilder
+ .dependedProductionComponent(new DependedProductionComponent() {
+ @Override public ListenableFuture<Integer> numGreetings() {
+ return Futures.immediateFuture(3);
+ }
+ })
+ .dependedComponent(new DependedComponent() {
+ @Override public String getGreeting() {
+ return "Goodbye world!";
+ }
+ })
+ .build();
+
+ assertThat(componentUsingJavaImpls.greetings().get()).containsExactly(
+ "3", "Goodbye world!", "GOODBYE WORLD!");
+ assertThat(componentUsingComponents.greetings().get()).containsExactly(
+ "2", "Hello world!", "HELLO WORLD!");
+
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/MultibindingTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/MultibindingTest.java
new file mode 100644
index 0000000..4ddc7c6
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/MultibindingTest.java
@@ -0,0 +1,73 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.MoreExecutors;
+import dagger.producers.Produced;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class MultibindingTest {
+ @Test
+ public void setBinding() throws Exception {
+ MultibindingComponent multibindingComponent =
+ DaggerMultibindingComponent.builder().executor(MoreExecutors.directExecutor()).build();
+ assertThat(multibindingComponent.strs().get())
+ .containsExactly("foo", "foo1", "foo2", "bar", "bar1", "bar2");
+ assertThat(multibindingComponent.strCount().get()).isEqualTo(6);
+ }
+
+ @Test
+ public void setBindingOfProduced() throws Exception {
+ MultibindingComponent multibindingComponent =
+ DaggerMultibindingComponent.builder().executor(MoreExecutors.directExecutor()).build();
+ assertThat(multibindingComponent.successfulSet().get())
+ .containsExactly(
+ Produced.successful("foo"),
+ Produced.successful("foo1"),
+ Produced.successful("foo2"),
+ Produced.successful("bar"),
+ Produced.successful("bar1"),
+ Produced.successful("bar2"));
+ }
+
+ @Test
+ public void setBindingOfProducedWithFailures() throws Exception {
+ MultibindingComponent multibindingComponent =
+ DaggerMultibindingComponent.builder().executor(MoreExecutors.directExecutor()).build();
+ Set<Produced<String>> possiblyThrowingSet = multibindingComponent.possiblyThrowingSet().get();
+ Set<String> successes = new HashSet<>();
+ Set<ExecutionException> failures = new HashSet<>();
+ for (Produced<String> str : possiblyThrowingSet) {
+ try {
+ successes.add(str.get());
+ } catch (ExecutionException e) {
+ failures.add(e);
+ }
+ }
+ assertThat(successes).containsExactly("singleton", "double", "ton");
+ assertThat(failures).hasSize(1);
+ assertThat(Iterables.getOnlyElement(failures).getCause()).hasMessage("monkey");
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/ProducerFactoryTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/ProducerFactoryTest.java
new file mode 100644
index 0000000..9a56029
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/ProducerFactoryTest.java
@@ -0,0 +1,185 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.concurrent.ExecutionException;
+import javax.inject.Provider;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.when;
+
+@RunWith(JUnit4.class)
+public class ProducerFactoryTest {
+ @Mock private ProductionComponentMonitor componentMonitor;
+ private ProducerMonitor monitor;
+ private Provider<ProductionComponentMonitor> componentMonitorProvider;
+
+ @Before
+ public void setUpMocks() {
+ MockitoAnnotations.initMocks(this);
+ monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
+ when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
+ componentMonitorProvider =
+ new Provider<ProductionComponentMonitor>() {
+ @Override
+ public ProductionComponentMonitor get() {
+ return componentMonitor;
+ }
+ };
+ }
+
+ @Test
+ public void noArgMethod() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_StrFactory.class);
+ Producer<String> producer =
+ new SimpleProducerModule_StrFactory(
+ MoreExecutors.directExecutor(), componentMonitorProvider);
+ assertThat(producer.get().get()).isEqualTo("str");
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ order.verify(monitor).succeeded("str");
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test public void singleArgMethod() throws Exception {
+ SettableFuture<Integer> intFuture = SettableFuture.create();
+ Producer<Integer> intProducer = producerOfFuture(intFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_StrWithArgFactory(
+ MoreExecutors.directExecutor(), componentMonitorProvider, intProducer);
+ assertThat(producer.get().isDone()).isFalse();
+ intFuture.set(42);
+ assertThat(producer.get().get()).isEqualTo("str with arg");
+ }
+
+ @Test
+ public void successMonitor() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
+
+ SettableFuture<String> strFuture = SettableFuture.create();
+ SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
+ Producer<SettableFuture<String>> strFutureProducer = producerOfFuture(strFutureFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_SettableFutureStrFactory(
+ MoreExecutors.directExecutor(), componentMonitorProvider, strFutureProducer);
+ assertThat(producer.get().isDone()).isFalse();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ strFutureFuture.set(strFuture);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ assertThat(producer.get().isDone()).isFalse();
+
+ strFuture.set("monkey");
+ assertThat(producer.get().get()).isEqualTo("monkey");
+ order.verify(monitor).succeeded("monkey");
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void failureMonitor() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
+
+ SettableFuture<String> strFuture = SettableFuture.create();
+ SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
+ Producer<SettableFuture<String>> strFutureProducer = producerOfFuture(strFutureFuture);
+ Producer<String> producer =
+ new SimpleProducerModule_SettableFutureStrFactory(
+ MoreExecutors.directExecutor(), componentMonitorProvider, strFutureProducer);
+ assertThat(producer.get().isDone()).isFalse();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ strFutureFuture.set(strFuture);
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+ assertThat(producer.get().isDone()).isFalse();
+
+ Throwable t = new RuntimeException("monkey");
+ strFuture.setException(t);
+ try {
+ producer.get().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(t);
+ order.verify(monitor).failed(t);
+ }
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void failureMonitorDueToThrowingProducer() throws Exception {
+ ProducerToken token = ProducerToken.create(SimpleProducerModule_ThrowingProducerFactory.class);
+
+ Producer<String> producer =
+ new SimpleProducerModule_ThrowingProducerFactory(
+ MoreExecutors.directExecutor(), componentMonitorProvider);
+ assertThat(producer.get().isDone()).isTrue();
+
+ InOrder order = inOrder(componentMonitor, monitor);
+ order.verify(componentMonitor).producerMonitorFor(token);
+
+ order.verify(monitor).methodStarting();
+ order.verify(monitor).methodFinished();
+
+ try {
+ producer.get().get();
+ fail();
+ } catch (ExecutionException e) {
+ order.verify(monitor).failed(e.getCause());
+ }
+
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void nullComponentMonitorProvider() throws Exception {
+ new SimpleProducerModule_StrFactory(MoreExecutors.directExecutor(), null);
+ }
+
+ private static <T> Producer<T> producerOfFuture(final ListenableFuture<T> future) {
+ return new Producer<T>() {
+ @Override public ListenableFuture<T> get() {
+ return future;
+ }
+ };
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/SimpleTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/SimpleTest.java
new file mode 100644
index 0000000..cacc0f1
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/SimpleTest.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package producerstest;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class SimpleTest {
+ @Test public void testSimpleComponent() throws Exception {
+ SimpleComponent simpleComponent = DaggerSimpleComponent
+ .builder()
+ .executor(MoreExecutors.directExecutor())
+ .build();
+ assertThat(simpleComponent).isNotNull();
+ assertThat(simpleComponent.response().get().data()).isEqualTo("Hello, Request #5!");
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/badexecutor/BadExecutorTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/badexecutor/BadExecutorTest.java
new file mode 100644
index 0000000..8a49797
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/badexecutor/BadExecutorTest.java
@@ -0,0 +1,74 @@
+package producerstest.badexecutor;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/** This test verifies behavior when the executor throws {@link RejectedExecutionException}. */
+@RunWith(JUnit4.class)
+public final class BadExecutorTest {
+ private SimpleComponent component;
+
+ @Before
+ public void setUpComponent() {
+ ComponentDependency dependency =
+ new ComponentDependency() {
+ @Override
+ public ListenableFuture<Double> doubleDep() {
+ return Futures.immediateFuture(42.0);
+ }
+ };
+ ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService();
+ component =
+ DaggerSimpleComponent.builder()
+ .executor(executorService)
+ .componentDependency(dependency)
+ .build();
+ executorService.shutdown();
+ }
+
+ @Test
+ public void rejectNoArgMethod() throws Exception {
+ try {
+ component.noArgStr().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(RejectedExecutionException.class);
+ }
+ }
+
+ @Test
+ public void rejectSingleArgMethod() throws Exception {
+ try {
+ component.singleArgInt().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(RejectedExecutionException.class);
+ }
+ }
+
+ @Test
+ public void rejectSingleArgFromComponentDepMethod() throws Exception {
+ try {
+ component.singleArgBool().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(RejectedExecutionException.class);
+ }
+ }
+
+ @Test
+ public void doNotRejectComponentDepMethod() throws Exception {
+ assertThat(component.doubleDep().get()).isEqualTo(42.0);
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/builder/ProductionComponentBuilderTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/builder/ProductionComponentBuilderTest.java
new file mode 100644
index 0000000..715761d
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/builder/ProductionComponentBuilderTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.builder;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/** Tests for {@link dagger.producers.ProductionComponent.Builder}. */
+@RunWith(JUnit4.class)
+public final class ProductionComponentBuilderTest {
+
+ @Test
+ public void successfulBuild() throws Exception {
+ TestComponentWithBuilder component =
+ DaggerTestComponentWithBuilder.builder()
+ .executor(MoreExecutors.directExecutor())
+ .depComponent(depComponent(15.3))
+ .strModule(new StringModule())
+ .build();
+ assertThat(component.s().get()).isEqualTo("arg: 42");
+ assertThat(component.d().get()).isEqualTo(15.3);
+ }
+
+ @Test
+ public void successfulBuild_withMissingZeroArgModule() throws Exception {
+ TestComponentWithBuilder component =
+ DaggerTestComponentWithBuilder.builder()
+ .executor(MoreExecutors.directExecutor())
+ .depComponent(depComponent(15.3))
+ .build();
+ assertThat(component.s().get()).isEqualTo("arg: 42");
+ assertThat(component.d().get()).isEqualTo(15.3);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void missingExecutor() {
+ DaggerTestComponentWithBuilder.builder()
+ .depComponent(depComponent(15.3))
+ .strModule(new StringModule())
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void missingDepComponent() {
+ DaggerTestComponentWithBuilder.builder()
+ .executor(MoreExecutors.directExecutor())
+ .strModule(new StringModule())
+ .build();
+ }
+
+ private static DepComponent depComponent(final double value) {
+ return new DepComponent() {
+ @Override
+ public ListenableFuture<Double> d() {
+ return Futures.immediateFuture(value);
+ }
+ };
+ }
+}
diff --git a/compiler/src/it/producers-functional-tests/src/test/java/producerstest/monitoring/MonitoringTest.java b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/monitoring/MonitoringTest.java
new file mode 100644
index 0000000..3efb2b5
--- /dev/null
+++ b/compiler/src/it/producers-functional-tests/src/test/java/producerstest/monitoring/MonitoringTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package producerstest.monitoring;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/** Tests for production components using monitoring. */
+@RunWith(JUnit4.class)
+public final class MonitoringTest {
+ @Mock private ProductionComponentMonitor.Factory componentMonitorFactory;
+ @Mock private StringStub server1;
+ @Mock private StringStub server2;
+ private SettableFuture<String> server1Future;
+ private SettableFuture<String> server2Future;
+ private FakeProductionComponentMonitor componentMonitor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ componentMonitor = new FakeProductionComponentMonitor();
+ when(componentMonitorFactory.create(any())).thenReturn(componentMonitor);
+ server1Future = SettableFuture.create();
+ server2Future = SettableFuture.create();
+ when(server1.run(any(String.class))).thenReturn(server1Future);
+ when(server2.run(any(String.class))).thenReturn(server2Future);
+ }
+
+ @Test
+ public void basicMonitoring() throws Exception {
+ MonitoredComponent component =
+ DaggerMonitoredComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .monitoringModule(new MonitoringModule(componentMonitorFactory))
+ .stubModule(new StubModule(server1, server2))
+ .build();
+ ListenableFuture<String> output = component.output();
+ assertThat(componentMonitor.monitors).hasSize(3);
+ ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries =
+ ImmutableList.copyOf(componentMonitor.monitors.entrySet());
+ assertThat(entries.get(0).getKey().toString()).contains("CallServer2");
+ assertThat(entries.get(1).getKey().toString()).contains("CallServer1");
+ assertThat(entries.get(2).getKey().toString()).contains("RequestData");
+
+ ProducerMonitor callServer2Monitor = entries.get(0).getValue();
+ ProducerMonitor callServer1Monitor = entries.get(1).getValue();
+ ProducerMonitor requestDataMonitor = entries.get(2).getValue();
+
+ InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+ inOrder.verify(requestDataMonitor).methodStarting();
+ inOrder.verify(requestDataMonitor).methodFinished();
+ inOrder.verify(requestDataMonitor).succeeded("Hello, World!");
+ inOrder.verify(callServer1Monitor).methodStarting();
+ inOrder.verify(callServer1Monitor).methodFinished();
+ verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+
+ server1Future.set("server 1 response");
+ inOrder.verify(callServer1Monitor).succeeded("server 1 response");
+ inOrder.verify(callServer2Monitor).methodStarting();
+ inOrder.verify(callServer2Monitor).methodFinished();
+ verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+
+ server2Future.set("server 2 response");
+ inOrder.verify(callServer2Monitor).succeeded("server 2 response");
+ verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+ assertThat(output.get()).isEqualTo("server 2 response");
+ }
+
+ @Test
+ public void basicMonitoringWithFailure() throws Exception {
+ MonitoredComponent component =
+ DaggerMonitoredComponent.builder()
+ .executor(MoreExecutors.directExecutor())
+ .monitoringModule(new MonitoringModule(componentMonitorFactory))
+ .stubModule(new StubModule(server1, server2))
+ .build();
+ ListenableFuture<String> output = component.output();
+ assertThat(componentMonitor.monitors).hasSize(3);
+ ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries =
+ ImmutableList.copyOf(componentMonitor.monitors.entrySet());
+ assertThat(entries.get(0).getKey().toString()).contains("CallServer2");
+ assertThat(entries.get(1).getKey().toString()).contains("CallServer1");
+ assertThat(entries.get(2).getKey().toString()).contains("RequestData");
+
+ ProducerMonitor callServer2Monitor = entries.get(0).getValue();
+ ProducerMonitor callServer1Monitor = entries.get(1).getValue();
+ ProducerMonitor requestDataMonitor = entries.get(2).getValue();
+
+ InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+ inOrder.verify(requestDataMonitor).methodStarting();
+ inOrder.verify(requestDataMonitor).methodFinished();
+ inOrder.verify(requestDataMonitor).succeeded("Hello, World!");
+ inOrder.verify(callServer1Monitor).methodStarting();
+ inOrder.verify(callServer1Monitor).methodFinished();
+ verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+
+ RuntimeException cause = new RuntimeException("monkey");
+ server1Future.setException(cause);
+ inOrder.verify(callServer1Monitor).failed(cause);
+ inOrder.verify(callServer2Monitor).failed(any(Throwable.class));
+ verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
+ try {
+ output.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(Throwables.getRootCause(e)).isSameAs(cause);
+ }
+ }
+
+ private static final class FakeProductionComponentMonitor implements ProductionComponentMonitor {
+ final Map<ProducerToken, ProducerMonitor> monitors = new LinkedHashMap<>();
+
+ @Override
+ public ProducerMonitor producerMonitorFor(ProducerToken token) {
+ ProducerMonitor monitor = mock(ProducerMonitor.class);
+ monitors.put(token, monitor);
+ return monitor;
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java
new file mode 100644
index 0000000..578fb5f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import java.lang.annotation.Annotation;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@link ProcessingStep} that is responsible for dealing with a component or production component
+ * as part of the {@link ComponentProcessor}.
+ */
+abstract class AbstractComponentProcessingStep implements ProcessingStep {
+
+ private final Class<? extends Annotation> componentAnnotation;
+ private final Messager messager;
+ private final ComponentHierarchyValidator componentHierarchyValidator;
+ private final BindingGraphValidator bindingGraphValidator;
+ private final ComponentDescriptor.Factory componentDescriptorFactory;
+ private final BindingGraph.Factory bindingGraphFactory;
+ private final ComponentGenerator componentGenerator;
+
+ AbstractComponentProcessingStep(
+ Class<? extends Annotation> componentAnnotation,
+ Messager messager,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ ComponentDescriptor.Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ this.componentAnnotation = componentAnnotation;
+ this.messager = messager;
+ this.componentHierarchyValidator = componentHierarchyValidator;
+ this.bindingGraphValidator = bindingGraphValidator;
+ this.componentDescriptorFactory = componentDescriptorFactory;
+ this.bindingGraphFactory = bindingGraphFactory;
+ this.componentGenerator = componentGenerator;
+ }
+
+ @Override
+ public final ImmutableSet<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder();
+ ComponentElementValidator componentElementValidator =
+ componentElementValidator(elementsByAnnotation);
+ for (Element element : elementsByAnnotation.get(componentAnnotation)) {
+ TypeElement componentTypeElement = MoreElements.asType(element);
+ try {
+ if (componentElementValidator.validateComponent(componentTypeElement, messager)) {
+ ComponentDescriptor componentDescriptor =
+ componentDescriptorFactory.forComponent(componentTypeElement);
+ ValidationReport<TypeElement> hierarchyReport =
+ componentHierarchyValidator.validate(componentDescriptor);
+ hierarchyReport.printMessagesTo(messager);
+ if (hierarchyReport.isClean()) {
+ BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor);
+ ValidationReport<TypeElement> graphReport =
+ bindingGraphValidator.validate(bindingGraph);
+ graphReport.printMessagesTo(messager);
+ if (graphReport.isClean()) {
+ generateComponent(bindingGraph);
+ }
+ }
+ }
+ } catch (TypeNotPresentException e) {
+ rejectedElements.add(componentTypeElement);
+ }
+ }
+ return rejectedElements.build();
+ }
+
+ private void generateComponent(BindingGraph bindingGraph) {
+ try {
+ componentGenerator.generate(bindingGraph);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+
+ /**
+ * Returns an object that can validate a type element annotated with the component type.
+ */
+ protected abstract ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation);
+
+ /**
+ * Validates a component type element.
+ */
+ protected static abstract class ComponentElementValidator {
+ /**
+ * Validates a component type element. Prints any messages about the element to
+ * {@code messager}.
+ *
+ * @throws TypeNotPresentException if any type required to validate the component cannot be
+ * found
+ */
+ abstract boolean validateComponent(TypeElement componentTypeElement, Messager messager);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java
new file mode 100644
index 0000000..db890b2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/AbstractComponentWriter.java
@@ -0,0 +1,1165 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+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.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.MembersInjector;
+import dagger.internal.DelegateFactory;
+import dagger.internal.Factory;
+import dagger.internal.InstanceFactory;
+import dagger.internal.MapFactory;
+import dagger.internal.MapProviderFactory;
+import dagger.internal.MembersInjectors;
+import dagger.internal.ScopedProvider;
+import dagger.internal.SetFactory;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ComponentGenerator.MemberSelect;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.StringLiteral;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.VoidName;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import dagger.producers.internal.SetOfProducedProducer;
+import dagger.producers.internal.SetProducer;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+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.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+import static com.google.auto.common.MoreTypes.asDeclared;
+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.checkState;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.DELEGATED;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.INITIALIZED;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
+import static dagger.internal.codegen.Binding.bindingPackageFor;
+import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticMethodInvocationWithCast;
+import static dagger.internal.codegen.ComponentGenerator.MemberSelect.staticSelect;
+import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.ENUM_INSTANCE;
+import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
+import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD;
+import static dagger.internal.codegen.MapKeys.getMapKeySnippet;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.indexDependenciesByUnresolvedKey;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static dagger.internal.codegen.Util.getKeyTypeOfMap;
+import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap;
+import static dagger.internal.codegen.Util.isMapWithNonProvidedValues;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+import static dagger.internal.codegen.writer.Snippet.memberSelectSnippet;
+import static dagger.internal.codegen.writer.Snippet.nullCheck;
+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.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * Creates the implementation class for a component or subcomponent.
+ */
+abstract class AbstractComponentWriter {
+ // TODO(dpb): Make all these fields private after refactoring is complete.
+ protected final Elements elements;
+ protected final Types types;
+ protected final Key.Factory keyFactory;
+ protected final Kind nullableValidationType;
+ protected final Set<JavaWriter> javaWriters = new LinkedHashSet<>();
+ protected final ClassName name;
+ protected final BindingGraph graph;
+ private final Map<BindingKey, InitializationState> initializationStates = new HashMap<>();
+ private final Map<Binding, InitializationState> contributionInitializationStates =
+ new HashMap<>();
+ protected ClassWriter componentWriter;
+ private final Map<BindingKey, MemberSelect> memberSelectSnippets = new HashMap<>();
+ private final Map<ContributionBinding, MemberSelect> multibindingContributionSnippets =
+ new HashMap<>();
+ protected ConstructorWriter constructorWriter;
+ protected Optional<ClassName> builderName = Optional.absent();
+
+ /**
+ * For each component requirement, the builder field. This map is empty for subcomponents that do
+ * not use a builder.
+ */
+ private ImmutableMap<TypeElement, FieldWriter> builderFields = ImmutableMap.of();
+
+ /**
+ * For each component requirement, the snippet for the component field that holds it.
+ *
+ * <p>Fields are written for all requirements for subcomponents that do not use a builder, and for
+ * any requirement that is reused from a subcomponent of this component.
+ */
+ protected final Map<TypeElement, MemberSelect> componentContributionFields = Maps.newHashMap();
+
+ AbstractComponentWriter(
+ Types types,
+ Elements elements,
+ Key.Factory keyFactory,
+ Diagnostic.Kind nullableValidationType,
+ ClassName name,
+ BindingGraph graph) {
+ this.types = types;
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ this.nullableValidationType = nullableValidationType;
+ this.name = name;
+ this.graph = graph;
+ }
+
+ protected final TypeElement componentDefinitionType() {
+ return graph.componentDescriptor().componentDefinitionType();
+ }
+
+ protected final ClassName componentDefinitionTypeName() {
+ return ClassName.fromTypeElement(componentDefinitionType());
+ }
+
+ /**
+ * Returns an expression snippet that evaluates to an instance of the contribution, looking for
+ * either a builder field or a component field.
+ */
+ private Snippet getComponentContributionSnippet(TypeElement contributionType) {
+ if (builderFields.containsKey(contributionType)) {
+ return Snippet.format("builder.%s", builderFields.get(contributionType).name());
+ } else {
+ Optional<Snippet> snippet = getOrCreateComponentContributionFieldSnippet(contributionType);
+ checkState(snippet.isPresent(), "no builder or component field for %s", contributionType);
+ return snippet.get();
+ }
+ }
+
+ /**
+ * Returns a snippet for a component contribution field. Adds a field the first time one is
+ * requested for a contribution type if this component's builder has a field for it.
+ */
+ protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet(
+ TypeElement contributionType) {
+ MemberSelect fieldSelect = componentContributionFields.get(contributionType);
+ if (fieldSelect == null) {
+ if (!builderFields.containsKey(contributionType)) {
+ return Optional.absent();
+ }
+ FieldWriter componentField =
+ componentWriter.addField(contributionType, simpleVariableName(contributionType));
+ componentField.addModifiers(PRIVATE, FINAL);
+ constructorWriter
+ .body()
+ .addSnippet(
+ "this.%s = builder.%s;",
+ componentField.name(),
+ builderFields.get(contributionType).name());
+ fieldSelect = MemberSelect.instanceSelect(name, Snippet.format("%s", componentField.name()));
+ componentContributionFields.put(contributionType, fieldSelect);
+ }
+ return Optional.of(fieldSelect.getSnippetFor(name));
+ }
+
+ private Snippet getMemberSelectSnippet(BindingKey key) {
+ return getMemberSelect(key).getSnippetFor(name);
+ }
+
+ protected MemberSelect getMemberSelect(BindingKey key) {
+ return memberSelectSnippets.get(key);
+ }
+
+ protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) {
+ return Optional.fromNullable(multibindingContributionSnippets.get(binding));
+ }
+
+ /**
+ * Returns the initialization state of the factory field for a binding key in this component.
+ */
+ protected InitializationState getInitializationState(BindingKey bindingKey) {
+ return initializationStates.containsKey(bindingKey)
+ ? initializationStates.get(bindingKey)
+ : UNINITIALIZED;
+ }
+
+ private void setInitializationState(BindingKey bindingKey, InitializationState state) {
+ initializationStates.put(bindingKey, state);
+ }
+
+ private InitializationState getContributionInitializationState(Binding binding) {
+ return contributionInitializationStates.containsKey(binding)
+ ? contributionInitializationStates.get(binding)
+ : UNINITIALIZED;
+ }
+
+ private void setContributionInitializationState(Binding binding, InitializationState state) {
+ contributionInitializationStates.put(binding, state);
+ }
+
+ ImmutableSet<JavaWriter> write() {
+ if (javaWriters.isEmpty()) {
+ writeComponent();
+ }
+ return ImmutableSet.copyOf(javaWriters);
+ }
+
+ private void writeComponent() {
+ componentWriter = createComponentClass();
+ addConstructor();
+ addBuilder();
+ addFactoryMethods();
+ addFields();
+ initializeFrameworkTypes();
+ implementInterfaceMethods();
+ addSubcomponents();
+ }
+
+ /**
+ * Creates the component implementation class.
+ */
+ protected abstract ClassWriter createComponentClass();
+
+ private void addConstructor() {
+ constructorWriter = componentWriter.addConstructor();
+ constructorWriter.addModifiers(PRIVATE);
+ }
+
+ /**
+ * Adds a builder type.
+ */
+ protected void addBuilder() {
+ ClassWriter builderWriter = createBuilder();
+ builderWriter.addModifiers(FINAL);
+ builderWriter.addConstructor().addModifiers(PRIVATE);
+ builderName = Optional.of(builderWriter.name());
+
+ Optional<BuilderSpec> builderSpec = graph.componentDescriptor().builderSpec();
+ if (builderSpec.isPresent()) {
+ builderWriter.addModifiers(PRIVATE);
+ builderWriter.setSupertype(builderSpec.get().builderDefinitionType());
+ } else {
+ builderWriter.addModifiers(PUBLIC);
+ }
+
+ builderFields = addBuilderFields(builderWriter);
+ addBuildMethod(builderWriter, builderSpec);
+ addBuilderMethods(builderWriter, builderSpec);
+
+ constructorWriter.addParameter(builderWriter, "builder");
+ constructorWriter.body().addSnippet("assert builder != null;");
+ }
+
+ /**
+ * Adds fields for each of the {@linkplain BindingGraph#componentRequirements component
+ * requirements}. Regardless of builder spec, there is always one field per requirement.
+ */
+ private ImmutableMap<TypeElement, FieldWriter> addBuilderFields(ClassWriter builderWriter) {
+ ImmutableMap.Builder<TypeElement, FieldWriter> builderFieldsBuilder = ImmutableMap.builder();
+ for (TypeElement contributionElement : graph.componentRequirements()) {
+ String contributionName = simpleVariableName(contributionElement);
+ FieldWriter builderField = builderWriter.addField(contributionElement, contributionName);
+ builderField.addModifiers(PRIVATE);
+ builderFieldsBuilder.put(contributionElement, builderField);
+ }
+ return builderFieldsBuilder.build();
+ }
+
+ /** Adds the build method to the builder. */
+ private void addBuildMethod(ClassWriter builderWriter, Optional<BuilderSpec> builderSpec) {
+ MethodWriter buildMethod;
+ if (builderSpec.isPresent()) {
+ ExecutableElement specBuildMethod = builderSpec.get().buildMethod();
+ // Note: we don't use the specBuildMethod.getReturnType() as the return type
+ // because it might be a type variable. We make use of covariant returns to allow
+ // us to return the component type, which will always be valid.
+ buildMethod =
+ builderWriter.addMethod(
+ componentDefinitionTypeName(), specBuildMethod.getSimpleName().toString());
+ buildMethod.annotate(Override.class);
+ } else {
+ buildMethod = builderWriter.addMethod(componentDefinitionTypeName(), "build");
+ }
+ buildMethod.addModifiers(PUBLIC);
+
+ for (Map.Entry<TypeElement, FieldWriter> builderFieldEntry : builderFields.entrySet()) {
+ FieldWriter builderField = builderFieldEntry.getValue();
+ if (componentCanMakeNewInstances(builderFieldEntry.getKey())) {
+ buildMethod.body()
+ .addSnippet("if (%1$s == null) { this.%1$s = new %2$s(); }",
+ builderField.name(),
+ builderField.type());
+ } else {
+ buildMethod.body()
+ .addSnippet(
+ "if (%s == null) { throw new %s(%s.class.getCanonicalName() + \" must be set\"); }",
+ builderField.name(),
+ ClassName.fromClass(IllegalStateException.class),
+ builderField.type());
+ }
+ }
+
+ buildMethod.body().addSnippet("return new %s(this);", name);
+ }
+
+ /**
+ * Adds the methods that set each of parameters on the builder. If the {@link BuilderSpec} is
+ * present, it will tailor the methods to match the spec.
+ */
+ private void addBuilderMethods(
+ ClassWriter builderWriter,
+ Optional<BuilderSpec> builderSpec) {
+ if (builderSpec.isPresent()) {
+ for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry :
+ builderSpec.get().methodMap().entrySet()) {
+ TypeElement builderMethodType = builderMethodEntry.getKey();
+ ExecutableElement specMethod = builderMethodEntry.getValue();
+ MethodWriter builderMethod = addBuilderMethodFromSpec(builderWriter, specMethod);
+ String parameterName =
+ Iterables.getOnlyElement(specMethod.getParameters()).getSimpleName().toString();
+ builderMethod.addParameter(builderMethodType, parameterName);
+ builderMethod.body().addSnippet(nullCheck(parameterName));
+ if (graph.componentRequirements().contains(builderMethodType)) {
+ // required type
+ builderMethod.body().addSnippet("this.%s = %s;",
+ builderFields.get(builderMethodType).name(),
+ parameterName);
+ addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
+ } else if (graph.ownedModuleTypes().contains(builderMethodType)) {
+ // owned, but not required
+ builderMethod.body()
+ .addSnippet("// This module is declared, but not used in the component. "
+ + "This method is a no-op");
+ addBuilderMethodReturnStatementForSpec(specMethod, builderMethod);
+ } else {
+ // neither owned nor required, so it must be an inherited module
+ builderMethod
+ .body()
+ .addSnippet(
+ "throw new %s(%s.format(%s, %s.class.getCanonicalName()));",
+ ClassName.fromClass(UnsupportedOperationException.class),
+ ClassName.fromClass(String.class),
+ StringLiteral.forValue(
+ "%s cannot be set because it is inherited from the enclosing component"),
+ ClassName.fromTypeElement(builderMethodType));
+ }
+ }
+ } else {
+ for (TypeElement componentRequirement : graph.availableDependencies()) {
+ String componentRequirementName = simpleVariableName(componentRequirement);
+ MethodWriter builderMethod = builderWriter.addMethod(
+ builderWriter.name(),
+ componentRequirementName);
+ builderMethod.addModifiers(PUBLIC);
+ builderMethod.addParameter(componentRequirement, componentRequirementName);
+ builderMethod.body().addSnippet(nullCheck(componentRequirementName));
+ if (graph.componentRequirements().contains(componentRequirement)) {
+ builderMethod.body()
+ .addSnippet("this.%s = %s;",
+ builderFields.get(componentRequirement).name(),
+ componentRequirementName);
+ } else {
+ builderMethod.annotate(Deprecated.class);
+ }
+ builderMethod.body().addSnippet("return this;");
+ }
+ }
+ }
+
+ private void addBuilderMethodReturnStatementForSpec(
+ ExecutableElement specMethod, MethodWriter builderMethod) {
+ if (!specMethod.getReturnType().getKind().equals(VOID)) {
+ builderMethod.body().addSnippet("return this;");
+ }
+ }
+
+ private MethodWriter addBuilderMethodFromSpec(
+ ClassWriter builderWriter, ExecutableElement method) {
+ String methodName = method.getSimpleName().toString();
+ TypeMirror returnType = method.getReturnType();
+ // If the return type is void, we add a method with the void return type.
+ // Otherwise we use the builderWriter and take advantage of covariant returns
+ // (so that we don't have to worry about setter methods that return type variables).
+ MethodWriter builderMethod =
+ returnType.getKind().equals(TypeKind.VOID)
+ ? builderWriter.addMethod(returnType, methodName)
+ : builderWriter.addMethod(builderWriter, methodName);
+ builderMethod.annotate(Override.class);
+ builderMethod.addModifiers(Sets.difference(method.getModifiers(), ImmutableSet.of(ABSTRACT)));
+ return builderMethod;
+ }
+
+ /**
+ * Creates the builder class.
+ */
+ protected abstract ClassWriter createBuilder();
+
+ /**
+ * Adds component factory methods.
+ */
+ protected abstract void addFactoryMethods();
+
+ private void addFields() {
+ for (ResolvedBindings resolvedBindings : graph.resolvedBindings().values()) {
+ addField(resolvedBindings);
+ }
+ }
+
+ private void addField(ResolvedBindings resolvedBindings) {
+ BindingKey bindingKey = resolvedBindings.bindingKey();
+
+ // No field needed if there are no owned bindings.
+ if (resolvedBindings.ownedBindings().isEmpty()) {
+ return;
+ }
+
+ // No field needed for bindings with no dependencies or state.
+ Optional<MemberSelect> staticMemberSelect = staticMemberSelect(resolvedBindings);
+ if (staticMemberSelect.isPresent()) {
+ memberSelectSnippets.put(bindingKey, staticMemberSelect.get());
+ return;
+ }
+
+ Optional<String> bindingPackage = bindingPackageFor(resolvedBindings.bindings());
+ boolean useRawType = bindingPackage.isPresent()
+ && !bindingPackage.get().equals(name.packageName());
+ if (bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION)) {
+ ImmutableSet<ContributionBinding> contributionBindings =
+ resolvedBindings.contributionBindings();
+ if (ContributionBinding.contributionTypeFor(contributionBindings).isMultibinding()) {
+ // note that here we rely on the order of the resolved bindings being from parent to child
+ // otherwise, the numbering wouldn't work
+ int contributionNumber = 0;
+ for (ContributionBinding contributionBinding : contributionBindings) {
+ if (!contributionBinding.isSyntheticBinding()) {
+ contributionNumber++;
+ if (resolvedBindings.ownedContributionBindings().contains(contributionBinding)) {
+ FrameworkField contributionBindingField =
+ FrameworkField.createForSyntheticContributionBinding(
+ contributionNumber, contributionBinding);
+ FieldWriter contributionField =
+ addFrameworkField(useRawType, contributionBindingField);
+
+ ImmutableList<String> contributionSelectTokens =
+ new ImmutableList.Builder<String>()
+ .add(contributionField.name())
+ .build();
+ multibindingContributionSnippets.put(
+ contributionBinding,
+ MemberSelect.instanceSelect(name, memberSelectSnippet(contributionSelectTokens)));
+ }
+ }
+ }
+ }
+ }
+
+ FrameworkField bindingField = FrameworkField.createForResolvedBindings(resolvedBindings);
+ FieldWriter frameworkField = addFrameworkField(useRawType, bindingField);
+
+ ImmutableList<String> memberSelectTokens =
+ new ImmutableList.Builder<String>()
+ .add(frameworkField.name())
+ .build();
+ memberSelectSnippets.put(
+ bindingKey,
+ MemberSelect.instanceSelect(name, Snippet.memberSelectSnippet(memberSelectTokens)));
+ }
+
+ private FieldWriter addFrameworkField(boolean useRawType,
+ FrameworkField contributionBindingField) {
+ FieldWriter contributionField =
+ componentWriter.addField(
+ useRawType
+ ? contributionBindingField.frameworkType().type()
+ : contributionBindingField.frameworkType(),
+ contributionBindingField.name());
+ contributionField.addModifiers(PRIVATE);
+ if (useRawType) {
+ contributionField.annotate(SuppressWarnings.class).setValue("rawtypes");
+ }
+ return contributionField;
+ }
+
+ /**
+ * 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 snippet that returns the factory or no-op members
+ * injector.
+ */
+ private Optional<MemberSelect> staticMemberSelect(ResolvedBindings resolvedBindings) {
+ switch (resolvedBindings.bindingKey().kind()) {
+ case CONTRIBUTION:
+ if (resolvedBindings.contributionBindings().size() != 1) {
+ return Optional.absent();
+ }
+ ContributionBinding contributionBinding =
+ getOnlyElement(resolvedBindings.contributionBindings());
+ if (contributionBinding.contributionType().isMultibinding()
+ || !(contributionBinding.bindingType().equals(Binding.Type.PROVISION))) {
+ return Optional.absent();
+ }
+ if (contributionBinding.factoryCreationStrategy().equals(ENUM_INSTANCE)
+ && !contributionBinding.scope().isPresent()) {
+ return Optional.of(
+ staticSelect(
+ generatedClassNameForBinding(contributionBinding), Snippet.format("create()")));
+ }
+ break;
+
+ case MEMBERS_INJECTION:
+ Optional<MembersInjectionBinding> membersInjectionBinding =
+ resolvedBindings.membersInjectionBinding();
+ if (membersInjectionBinding.isPresent()
+ && membersInjectionBinding.get().injectionStrategy().equals(NO_OP)) {
+ return Optional.of(
+ staticMethodInvocationWithCast(
+ ClassName.fromClass(MembersInjectors.class),
+ Snippet.format("noOp()"),
+ ClassName.fromClass(MembersInjector.class)));
+ }
+ break;
+
+ default:
+ throw new AssertionError();
+ }
+ return Optional.absent();
+ }
+
+ private void implementInterfaceMethods() {
+ Set<MethodSignature> interfaceMethods = Sets.newHashSet();
+ for (ComponentMethodDescriptor componentMethod :
+ graph.componentDescriptor().componentMethods()) {
+ if (componentMethod.dependencyRequest().isPresent()) {
+ DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get();
+ ExecutableElement requestElement =
+ MoreElements.asExecutable(interfaceRequest.requestElement());
+ ExecutableType requestType = MoreTypes.asExecutable(types.asMemberOf(
+ MoreTypes.asDeclared(componentDefinitionType().asType()), requestElement));
+ MethodSignature signature = MethodSignature.fromExecutableType(
+ requestElement.getSimpleName().toString(), requestType);
+ if (!interfaceMethods.contains(signature)) {
+ interfaceMethods.add(signature);
+ MethodWriter interfaceMethod =
+ requestType.getReturnType().getKind().equals(VOID)
+ ? componentWriter.addMethod(
+ VoidName.VOID, requestElement.getSimpleName().toString())
+ : componentWriter.addMethod(
+ requestType.getReturnType(), requestElement.getSimpleName().toString());
+ interfaceMethod.annotate(Override.class);
+ interfaceMethod.addModifiers(PUBLIC);
+ BindingKey bindingKey = interfaceRequest.bindingKey();
+ MemberSelect memberSelect = getMemberSelect(bindingKey);
+ Snippet memberSelectSnippet = memberSelect.getSnippetFor(name);
+ switch (interfaceRequest.kind()) {
+ case MEMBERS_INJECTOR:
+ List<? extends VariableElement> parameters = requestElement.getParameters();
+ if (parameters.isEmpty()) {
+ // we're returning the framework type
+ interfaceMethod.body().addSnippet("return %s;", memberSelectSnippet);
+ } else {
+ VariableElement parameter = Iterables.getOnlyElement(parameters);
+ Name parameterName = parameter.getSimpleName();
+ interfaceMethod.addParameter(
+ TypeNames.forTypeMirror(
+ Iterables.getOnlyElement(requestType.getParameterTypes())),
+ parameterName.toString());
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "%s.injectMembers(%s);",
+ memberSelectSnippet,
+ parameterName);
+ if (!requestType.getReturnType().getKind().equals(VOID)) {
+ interfaceMethod.body().addSnippet("return %s;", parameterName);
+ }
+ }
+ break;
+ case INSTANCE:
+ if (memberSelect.staticMember()
+ && bindingKey.key().type().getKind().equals(DECLARED)
+ && !((DeclaredType) bindingKey.key().type()).getTypeArguments().isEmpty()) {
+ // If using a parameterized enum type, then we need to store the factory
+ // in a temporary variable, in order to help javac be able to infer
+ // the generics of the Factory.create methods.
+ TypeName factoryType =
+ ParameterizedTypeName.create(
+ Provider.class, TypeNames.forTypeMirror(requestType.getReturnType()));
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "%s factory = %s;", factoryType, memberSelectSnippet);
+ interfaceMethod.body().addSnippet("return factory.get();");
+ break;
+ }
+ // fall through in the else case.
+ case LAZY:
+ case PRODUCED:
+ case PRODUCER:
+ case PROVIDER:
+ case FUTURE:
+ interfaceMethod
+ .body()
+ .addSnippet(
+ "return %s;",
+ frameworkTypeUsageStatement(
+ memberSelectSnippet, interfaceRequest.kind()));
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+ }
+ }
+
+ private void addSubcomponents() {
+ for (Map.Entry<ExecutableElement, BindingGraph> subgraphEntry : graph.subgraphs().entrySet()) {
+ SubcomponentWriter subcomponent =
+ new SubcomponentWriter(this, subgraphEntry.getKey(), subgraphEntry.getValue());
+ javaWriters.addAll(subcomponent.write());
+ }
+ }
+
+ private static final int SNIPPETS_PER_INITIALIZATION_METHOD = 100;
+
+ private void initializeFrameworkTypes() {
+ ImmutableList.Builder<Snippet> snippetsBuilder = ImmutableList.builder();
+ for (BindingKey bindingKey : graph.resolvedBindings().keySet()) {
+ snippetsBuilder.add(initializeFrameworkType(bindingKey));
+ }
+ ImmutableList<Snippet> snippets = snippetsBuilder.build();
+
+ List<List<Snippet>> partitions = Lists.partition(snippets, SNIPPETS_PER_INITIALIZATION_METHOD);
+ for (int i = 0; i < partitions.size(); i++) {
+ MethodWriter initializeMethod =
+ componentWriter.addMethod(VoidName.VOID, "initialize" + ((i == 0) ? "" : i));
+ /* 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 initilization
+ * as we do now. */
+ initializeMethod.annotate(SuppressWarnings.class).setValue("unchecked");
+ for (Snippet snippet : partitions.get(i)) {
+ initializeMethod.body().addSnippet(snippet);
+ }
+ initializeMethod.addModifiers(PRIVATE);
+ if (builderName.isPresent()) {
+ initializeMethod.addParameter(builderName.get(), "builder").addModifiers(FINAL);
+ constructorWriter.body().addSnippet("%s(builder);", initializeMethod.name());
+ } else {
+ constructorWriter.body().addSnippet("%s();", initializeMethod.name());
+ }
+ }
+ }
+
+ /**
+ * Returns a single snippet representing the initialization of the framework type.
+ *
+ * <p>Note that this must be a single snippet because initialization snippets can be invoked from
+ * any place in any order. By requiring a single snippet (often of concatenated snippets) we
+ * ensure that things like local variables always behave as expected by the initialization logic.
+ */
+ private Snippet initializeFrameworkType(BindingKey bindingKey) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey);
+
+ // There's no field for inherited bindings.
+ if (resolvedBindings.ownedBindings().isEmpty()) {
+ return Snippet.format("");
+ }
+
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ switch (contributionTypeFor(resolvedBindings.contributionBindings())) {
+ case SET:
+ return initializeSetMultibindings(resolvedBindings);
+ case MAP:
+ return initializeMapMultibindings(resolvedBindings);
+ case UNIQUE:
+ return initializeUniqueContributionBinding(resolvedBindings);
+ default:
+ throw new AssertionError();
+ }
+
+ case MEMBERS_INJECTION:
+ return initializeMembersInjectionBinding(resolvedBindings);
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private Snippet initializeSetMultibindings(ResolvedBindings resolvedBindings) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (ContributionBinding binding : resolvedBindings.contributionBindings()) {
+ Optional<MemberSelect> multibindingContributionSnippet =
+ getMultibindingContributionSnippet(binding);
+ checkState(multibindingContributionSnippet.isPresent(), "%s was not found", binding);
+ Snippet snippet = multibindingContributionSnippet.get().getSnippetFor(name);
+ if (multibindingContributionSnippet.get().owningClass().equals(name)
+ // the binding might already be initialized by a different set binding that shares the
+ // same contributions (e.g., Set<T> and Set<Produced<T>>)
+ && getContributionInitializationState(binding)
+ .equals(InitializationState.UNINITIALIZED)) {
+ Snippet initializeSnippet = initializeFactoryForContributionBinding(binding);
+ initializationSnippets.add(Snippet.format("this.%s = %s;", snippet, initializeSnippet));
+ setContributionInitializationState(binding, InitializationState.INITIALIZED);
+ }
+ parameterSnippets.add(snippet);
+ }
+ Class<?> factoryClass =
+ Iterables.all(resolvedBindings.contributionBindings(), Binding.Type.PROVISION)
+ ? SetFactory.class
+ : Util.isSetOfProduced(resolvedBindings.bindingKey().key().type())
+ ? SetOfProducedProducer.class
+ : SetProducer.class;
+ Snippet initializeSetSnippet =
+ Snippet.format(
+ "%s.create(%s)",
+ ClassName.fromClass(factoryClass),
+ makeParametersSnippet(parameterSnippets.build()));
+ initializationSnippets.add(
+ initializeMember(resolvedBindings.bindingKey(), initializeSetSnippet));
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet initializeMapMultibindings(ResolvedBindings resolvedBindings) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ if (any(resolvedBindings.contributionBindings(), Binding.Type.PRODUCTION)) {
+ // TODO(beder): Implement producer map bindings.
+ throw new IllegalStateException("producer map bindings not implemented yet");
+ }
+ for (ContributionBinding binding : resolvedBindings.contributionBindings()) {
+ Optional<MemberSelect> multibindingContributionSnippet =
+ getMultibindingContributionSnippet(binding);
+ if (!isMapWithNonProvidedValues(binding.key().type())
+ && multibindingContributionSnippet.isPresent()
+ && multibindingContributionSnippet.get().owningClass().equals(name)) {
+ initializationSnippets.add(
+ Snippet.format(
+ "this.%s = %s;",
+ multibindingContributionSnippet.get().getSnippetFor(name),
+ initializeFactoryForContributionBinding(binding)));
+ }
+ }
+ initializationSnippets.add(
+ initializeMember(
+ resolvedBindings.bindingKey(),
+ initializeMapBinding(resolvedBindings.contributionBindings())));
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet initializeUniqueContributionBinding(ResolvedBindings resolvedBindings) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ ContributionBinding binding = getOnlyElement(resolvedBindings.ownedContributionBindings());
+ if (!binding.factoryCreationStrategy().equals(ENUM_INSTANCE) || binding.scope().isPresent()) {
+ initializationSnippets.add(initializeDelegateFactories(binding));
+ initializationSnippets.add(
+ initializeMember(
+ resolvedBindings.bindingKey(), initializeFactoryForContributionBinding(binding)));
+ }
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet initializeMembersInjectionBinding(ResolvedBindings resolvedBindings) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ MembersInjectionBinding binding = resolvedBindings.membersInjectionBinding().get();
+ if (!binding.injectionStrategy().equals(MembersInjectionBinding.Strategy.NO_OP)) {
+ initializationSnippets.add(initializeDelegateFactories(binding));
+ initializationSnippets.add(
+ initializeMember(
+ resolvedBindings.bindingKey(), initializeMembersInjectorForBinding(binding)));
+ }
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet initializeDelegateFactories(Binding binding) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ for (Collection<DependencyRequest> requestsForKey :
+ indexDependenciesByUnresolvedKey(types, binding.dependencies()).asMap().values()) {
+ BindingKey dependencyKey =
+ Iterables.getOnlyElement(
+ FluentIterable.from(requestsForKey)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION)
+ .toSet());
+ if (!getMemberSelect(dependencyKey).staticMember()
+ && getInitializationState(dependencyKey).equals(UNINITIALIZED)) {
+ initializationSnippets.add(
+ Snippet.format(
+ "this.%s = new %s();",
+ getMemberSelectSnippet(dependencyKey),
+ ClassName.fromClass(DelegateFactory.class)));
+ setInitializationState(dependencyKey, DELEGATED);
+ }
+ }
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet initializeMember(BindingKey bindingKey, Snippet initializationSnippet) {
+ ImmutableList.Builder<Snippet> initializationSnippets = ImmutableList.builder();
+
+ Snippet memberSelect = getMemberSelectSnippet(bindingKey);
+ Snippet delegateFactoryVariable = delegateFactoryVariableSnippet(bindingKey);
+ if (getInitializationState(bindingKey).equals(DELEGATED)) {
+ initializationSnippets.add(
+ Snippet.format(
+ "%1$s %2$s = (%1$s) %3$s;",
+ ClassName.fromClass(DelegateFactory.class),
+ delegateFactoryVariable,
+ memberSelect));
+ }
+ initializationSnippets.add(
+ Snippet.format("this.%s = %s;", memberSelect, initializationSnippet));
+ if (getInitializationState(bindingKey).equals(DELEGATED)) {
+ initializationSnippets.add(
+ Snippet.format("%s.setDelegatedProvider(%s);", delegateFactoryVariable, memberSelect));
+ }
+ setInitializationState(bindingKey, INITIALIZED);
+
+ return Snippet.concat(initializationSnippets.build());
+ }
+
+ private Snippet delegateFactoryVariableSnippet(BindingKey key) {
+ return Snippet.format("%sDelegate", getMemberSelectSnippet(key).toString().replace('.', '_'));
+ }
+
+ private Snippet initializeFactoryForContributionBinding(ContributionBinding binding) {
+ TypeName bindingKeyTypeName = TypeNames.forTypeMirror(binding.key().type());
+ switch (binding.bindingKind()) {
+ case COMPONENT:
+ return Snippet.format(
+ "%s.<%s>create(%s)",
+ ClassName.fromClass(InstanceFactory.class),
+ bindingKeyTypeName,
+ bindingKeyTypeName.equals(componentDefinitionTypeName())
+ ? "this"
+ : getComponentContributionSnippet(MoreTypes.asTypeElement(binding.key().type())));
+
+ case COMPONENT_PROVISION:
+ {
+ TypeElement bindingTypeElement =
+ graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
+ String localFactoryVariable = simpleVariableName(bindingTypeElement);
+ Snippet callFactoryMethodSnippet =
+ Snippet.format(
+ "%s.%s()",
+ localFactoryVariable,
+ binding.bindingElement().getSimpleName().toString());
+ // TODO(sameb): This throws a very vague NPE right now. 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?
+ StringLiteral failMsg =
+ StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
+ Snippet getMethodBody =
+ binding.nullableType().isPresent()
+ || nullableValidationType.equals(Diagnostic.Kind.WARNING)
+ ? Snippet.format("return %s;", callFactoryMethodSnippet)
+ : Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "%s provided = %s;",
+ "if (provided == null) {",
+ " throw new NullPointerException(%s);",
+ "}",
+ "return provided;"),
+ bindingKeyTypeName,
+ callFactoryMethodSnippet,
+ failMsg);
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " private final %5$s %6$s = %3$s;",
+ " %4$s@Override public %2$s get() {",
+ " %7$s",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Factory.class),
+ /* 2 */ bindingKeyTypeName,
+ /* 3 */ getComponentContributionSnippet(bindingTypeElement),
+ /* 4 */ nullableSnippet(binding.nullableType()),
+ /* 5 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
+ /* 6 */ localFactoryVariable,
+ /* 7 */ getMethodBody);
+ }
+
+ case SUBCOMPONENT_BUILDER:
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " @Override public %2$s get() {",
+ " return %3$s();",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Factory.class),
+ /* 2 */ bindingKeyTypeName,
+ /* 3 */ binding.bindingElement().getSimpleName().toString());
+
+ case INJECTION:
+ case PROVISION:
+ {
+ List<Snippet> parameters =
+ Lists.newArrayListWithCapacity(binding.dependencies().size() + 1);
+ if (binding.bindingKind().equals(PROVISION)
+ && !binding.bindingElement().getModifiers().contains(STATIC)) {
+ parameters.add(getComponentContributionSnippet(binding.contributedBy().get()));
+ }
+ parameters.addAll(getDependencyParameters(binding));
+
+ Snippet factorySnippet =
+ Snippet.format(
+ "%s.create(%s)",
+ generatedClassNameForBinding(binding),
+ Snippet.makeParametersSnippet(parameters));
+ return binding.scope().isPresent()
+ ? Snippet.format(
+ "%s.create(%s)", ClassName.fromClass(ScopedProvider.class), factorySnippet)
+ : factorySnippet;
+ }
+
+ case COMPONENT_PRODUCTION:
+ {
+ TypeElement bindingTypeElement =
+ graph.componentDescriptor().dependencyMethodIndex().get(binding.bindingElement());
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s>() {",
+ " private final %6$s %7$s = %4$s;",
+ " @Override public %3$s<%2$s> get() {",
+ " return %7$s.%5$s();",
+ " }",
+ "}"),
+ /* 1 */ ClassName.fromClass(Producer.class),
+ /* 2 */ TypeNames.forTypeMirror(binding.key().type()),
+ /* 3 */ ClassName.fromClass(ListenableFuture.class),
+ /* 4 */ getComponentContributionSnippet(bindingTypeElement),
+ /* 5 */ binding.bindingElement().getSimpleName().toString(),
+ /* 6 */ TypeNames.forTypeMirror(bindingTypeElement.asType()),
+ /* 7 */ simpleVariableName(bindingTypeElement));
+ }
+
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ {
+ List<Snippet> parameters =
+ Lists.newArrayListWithCapacity(binding.implicitDependencies().size() + 2);
+ if (!binding.bindingElement().getModifiers().contains(STATIC)) {
+ parameters.add(getComponentContributionSnippet(binding.bindingTypeElement()));
+ }
+ parameters.add(
+ getComponentContributionSnippet(
+ graph.componentDescriptor().executorDependency().get()));
+ parameters.addAll(getProducerDependencyParameters(binding));
+
+ return Snippet.format(
+ "new %s(%s)",
+ generatedClassNameForBinding(binding),
+ Snippet.makeParametersSnippet(parameters));
+ }
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private Snippet nullableSnippet(Optional<DeclaredType> nullableType) {
+ return nullableType.isPresent()
+ ? Snippet.format("@%s ", TypeNames.forTypeMirror(nullableType.get()))
+ : Snippet.format("");
+ }
+
+ private Snippet initializeMembersInjectorForBinding(MembersInjectionBinding binding) {
+ switch (binding.injectionStrategy()) {
+ case NO_OP:
+ return Snippet.format("%s.noOp()", ClassName.fromClass(MembersInjectors.class));
+ case INJECT_MEMBERS:
+ List<Snippet> parameters = getDependencyParameters(binding);
+ return Snippet.format(
+ "%s.create(%s)",
+ membersInjectorNameForType(binding.bindingElement()),
+ Snippet.makeParametersSnippet(parameters));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private List<Snippet> getDependencyParameters(Binding binding) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ Set<Key> keysSeen = new HashSet<>();
+ for (Collection<DependencyRequest> requestsForKey :
+ indexDependenciesByUnresolvedKey(types, binding.implicitDependencies()).asMap().values()) {
+ Set<BindingKey> requestedBindingKeys = new HashSet<>();
+ for (DependencyRequest dependencyRequest : requestsForKey) {
+ Element requestElement = dependencyRequest.requestElement();
+ TypeMirror typeMirror = typeMirrorAsMemberOf(binding.bindingTypeElement(), requestElement);
+ Key key = keyFactory.forQualifiedType(dependencyRequest.key().qualifier(), typeMirror);
+ if (keysSeen.add(key)) {
+ requestedBindingKeys.add(dependencyRequest.bindingKey());
+ }
+ }
+ if (!requestedBindingKeys.isEmpty()) {
+ BindingKey key = Iterables.getOnlyElement(requestedBindingKeys);
+ parameters.add(getMemberSelect(key).getSnippetWithRawTypeCastFor(name));
+ }
+ }
+ return parameters.build();
+ }
+
+ // TODO(dpb): Investigate use of asMemberOf here. Why aren't the dependency requests already
+ // resolved?
+ private TypeMirror typeMirrorAsMemberOf(TypeElement bindingTypeElement, Element requestElement) {
+ TypeMirror requestType = requestElement.asType();
+ if (requestType.getKind() == TypeKind.TYPEVAR) {
+ return types.asMemberOf(
+ MoreTypes.asDeclared(bindingTypeElement.asType()),
+ (requestElement.getKind() == ElementKind.PARAMETER)
+ ? MoreTypes.asElement(requestType)
+ : requestElement);
+ } else {
+ return requestType;
+ }
+ }
+
+ private List<Snippet> getProducerDependencyParameters(Binding binding) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (Collection<DependencyRequest> requestsForKey :
+ SourceFiles.indexDependenciesByUnresolvedKey(types, binding.implicitDependencies())
+ .asMap()
+ .values()) {
+ BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION));
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(key);
+ Class<?> frameworkClass =
+ DependencyRequestMapper.FOR_PRODUCER.getFrameworkClass(requestsForKey);
+ if (FrameworkField.frameworkClassForResolvedBindings(resolvedBindings).equals(Provider.class)
+ && frameworkClass.equals(Producer.class)) {
+ parameters.add(
+ Snippet.format(
+ "%s.producerFromProvider(%s)",
+ ClassName.fromClass(Producers.class),
+ getMemberSelectSnippet(key)));
+ } else {
+ parameters.add(getMemberSelectSnippet(key));
+ }
+ }
+ return parameters.build();
+ }
+
+ private Snippet initializeMapBinding(Set<ContributionBinding> bindings) {
+ // Get type information from the first binding.
+ ContributionBinding firstBinding = bindings.iterator().next();
+ DeclaredType mapType = asDeclared(firstBinding.key().type());
+
+ if (isMapWithNonProvidedValues(mapType)) {
+ return Snippet.format(
+ "%s.create(%s)",
+ ClassName.fromClass(MapFactory.class),
+ getMemberSelectSnippet(getOnlyElement(firstBinding.dependencies()).bindingKey()));
+ }
+
+ ImmutableList.Builder<dagger.internal.codegen.writer.Snippet> snippets =
+ ImmutableList.builder();
+ snippets.add(Snippet.format("%s.<%s, %s>builder(%d)",
+ ClassName.fromClass(MapProviderFactory.class),
+ TypeNames.forTypeMirror(getKeyTypeOfMap(mapType)),
+ TypeNames.forTypeMirror(getProvidedValueTypeOfMap(mapType)), // V of Map<K, Provider<V>>
+ bindings.size()));
+
+ for (ContributionBinding binding : bindings) {
+ snippets.add(
+ Snippet.format(
+ " .put(%s, %s)",
+ getMapKeySnippet(binding.bindingElement()),
+ getMultibindingContributionSnippet(binding).get().getSnippetFor(name)));
+ }
+
+ snippets.add(Snippet.format(" .build()"));
+
+ return Snippet.concat(snippets.build());
+ }
+
+ private static String simpleVariableName(TypeElement typeElement) {
+ return UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
+ }
+
+ /**
+ * Initialization state for a factory field.
+ */
+ enum InitializationState {
+ /** The field is {@code null}. */
+ UNINITIALIZED,
+
+ /** The field is set to a {@link DelegateFactory}. */
+ DELEGATED,
+
+ /** The field is set to an undelegated factory. */
+ INITIALIZED;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Binding.java b/compiler/src/main/java/dagger/internal/codegen/Binding.java
new file mode 100644
index 0000000..0a6b840
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Binding.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import dagger.MembersInjector;
+import dagger.producers.Producer;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+/**
+ * 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.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+abstract class Binding {
+
+ /**
+ * The subtype of this binding.
+ */
+ enum Type implements Predicate<Binding> {
+ /** A binding with this type is a {@link ProvisionBinding}. */
+ PROVISION(Provider.class),
+ /** A binding with this type is a {@link MembersInjectionBinding}. */
+ MEMBERS_INJECTION(MembersInjector.class),
+ /** A binding with this type is a {@link ProductionBinding}. */
+ PRODUCTION(Producer.class),
+ ;
+
+ private final Class<?> frameworkClass;
+
+ private Type(Class<?> frameworkClass) {
+ this.frameworkClass = frameworkClass;
+ }
+
+ /**
+ * Returns the framework class associated with bindings of this type.
+ */
+ Class<?> frameworkClass() {
+ return frameworkClass;
+ }
+
+ BindingKey.Kind bindingKeyKind() {
+ switch (this) {
+ case MEMBERS_INJECTION:
+ return BindingKey.Kind.MEMBERS_INJECTION;
+ case PROVISION:
+ case PRODUCTION:
+ return BindingKey.Kind.CONTRIBUTION;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public boolean apply(Binding binding) {
+ return this.equals(binding.bindingType());
+ }
+ }
+
+ abstract Binding.Type bindingType();
+
+ /**
+ * Returns the framework class associated with this binding.
+ */
+ Class<?> frameworkClass() {
+ return bindingType().frameworkClass();
+ }
+
+ static Optional<String> bindingPackageFor(Iterable<? extends Binding> bindings) {
+ ImmutableSet.Builder<String> bindingPackagesBuilder = ImmutableSet.builder();
+ for (Binding binding : bindings) {
+ bindingPackagesBuilder.addAll(binding.bindingPackage().asSet());
+ }
+ ImmutableSet<String> bindingPackages = bindingPackagesBuilder.build();
+ switch (bindingPackages.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.of(bindingPackages.iterator().next());
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /** The {@link Key} that is provided by this binding. */
+ protected abstract Key key();
+
+ BindingKey bindingKey() {
+ return BindingKey.create(bindingType().bindingKeyKind(), key());
+ }
+
+ /** Returns the {@link Element} instance that is responsible for declaring the binding. */
+ abstract Element bindingElement();
+
+ /** The type enclosing the binding {@link #bindingElement()}. */
+ TypeElement bindingTypeElement() {
+ return BINDING_TYPE_ELEMENT.visit(bindingElement());
+ }
+
+ private static final ElementVisitor<TypeElement, Void> BINDING_TYPE_ELEMENT =
+ new SimpleElementVisitor6<TypeElement, Void>() {
+ @Override
+ protected TypeElement defaultAction(Element e, Void p) {
+ return visit(e.getEnclosingElement());
+ }
+
+ @Override
+ public TypeElement visitType(TypeElement e, Void p) {
+ return e;
+ }
+ };
+
+ /**
+ * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding.
+ */
+ abstract ImmutableSet<DependencyRequest> dependencies();
+
+ /**
+ * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is a
+ * superset of {@link #dependencies()}. This returns an unmodifiable set.
+ */
+ abstract Set<DependencyRequest> implicitDependencies();
+
+ /**
+ * Returns the name of the package in which this binding must be managed. E.g.: a binding
+ * may reference non-public types.
+ */
+ abstract Optional<String> bindingPackage();
+
+ protected static Optional<String> findBindingPackage(Key bindingKey) {
+ Set<String> packages = nonPublicPackageUse(bindingKey.type());
+ switch (packages.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.of(packages.iterator().next());
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private static Set<String> nonPublicPackageUse(TypeMirror typeMirror) {
+ ImmutableSet.Builder<String> packages = ImmutableSet.builder();
+ typeMirror.accept(new SimpleTypeVisitor6<Void, ImmutableSet.Builder<String>>() {
+ @Override
+ public Void visitArray(ArrayType t, ImmutableSet.Builder<String> p) {
+ return t.getComponentType().accept(this, p);
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, ImmutableSet.Builder<String> p) {
+ for (TypeMirror typeArgument : t.getTypeArguments()) {
+ typeArgument.accept(this, p);
+ }
+ // TODO(gak): address public nested types in non-public types
+ TypeElement typeElement = MoreElements.asType(t.asElement());
+ if (!typeElement.getModifiers().contains(PUBLIC)) {
+ PackageElement elementPackage = MoreElements.getPackage(typeElement);
+ Name qualifiedName = elementPackage.getQualifiedName();
+ p.add(qualifiedName.toString());
+ }
+ // Also make sure enclosing types are visible, otherwise we're fooled by
+ // class Foo { public class Bar }
+ // (Note: we can't use t.getEnclosingType() because it doesn't work!)
+ typeElement.getEnclosingElement().asType().accept(this, p);
+ return null;
+ }
+
+ @Override
+ public Void visitWildcard(WildcardType t, ImmutableSet.Builder<String> p) {
+ if (t.getExtendsBound() != null) {
+ t.getExtendsBound().accept(this, p);
+ }
+ if (t.getSuperBound() != null) {
+ t.getSuperBound().accept(this, p);
+ }
+ return null;
+ }
+ }, packages);
+ return packages.build();
+ }
+
+ /**
+ * Returns true if this is a binding for a key that has a different type parameter list than the
+ * element it's providing.
+ */
+ abstract boolean hasNonDefaultTypeParameters();
+
+ /**
+ * The scope of this binding.
+ */
+ Scope scope() {
+ return Scope.unscoped();
+ }
+
+ // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
+ static boolean hasNonDefaultTypeParameters(TypeElement element, TypeMirror type, Types 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/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
new file mode 100644
index 0000000..b951438
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+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.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.TreeTraverser;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.internal.codegen.Binding.Type;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.producers.Producer;
+import dagger.producers.ProductionComponent;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+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.util.ElementFilter;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Sets.union;
+import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
+import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor.isOfKind;
+import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.INJECT_MEMBERS;
+import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * The canonical representation of a full-resolved graph.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class BindingGraph {
+ abstract ComponentDescriptor componentDescriptor();
+ abstract ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings();
+ abstract ImmutableMap<ExecutableElement, BindingGraph> subgraphs();
+
+ /**
+ * 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 Component
+ * components}, this set will be the same as
+ * {@linkplain ComponentDescriptor#transitiveModules 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();
+
+ ImmutableSet<TypeElement> ownedModuleTypes() {
+ return FluentIterable.from(ownedModules())
+ .transform(ModuleDescriptor.getModuleElement())
+ .toSet();
+ }
+
+ private static final TreeTraverser<BindingGraph> SUBGRAPH_TRAVERSER =
+ new TreeTraverser<BindingGraph>() {
+ @Override
+ public Iterable<BindingGraph> children(BindingGraph node) {
+ return node.subgraphs().values();
+ }
+ };
+
+ /**
+ * Returns the set of types necessary to implement the component, but are not part of the injected
+ * graph. This includes modules, component dependencies and an {@link Executor} in the case of
+ * {@link ProductionComponent}.
+ */
+ ImmutableSet<TypeElement> componentRequirements() {
+ return SUBGRAPH_TRAVERSER
+ .preOrderTraversal(this)
+ .transformAndConcat(
+ new Function<BindingGraph, Iterable<ResolvedBindings>>() {
+ @Override
+ public Iterable<ResolvedBindings> apply(BindingGraph input) {
+ return input.resolvedBindings().values();
+ }
+ })
+ .transformAndConcat(
+ new Function<ResolvedBindings, Set<ContributionBinding>>() {
+ @Override
+ public Set<ContributionBinding> apply(ResolvedBindings input) {
+ return (input.bindingKey().kind().equals(CONTRIBUTION))
+ ? input.contributionBindings()
+ : ImmutableSet.<ContributionBinding>of();
+ }
+ })
+ .transformAndConcat(
+ new Function<ContributionBinding, Set<TypeElement>>() {
+ @Override
+ public Set<TypeElement> apply(ContributionBinding input) {
+ return input.bindingElement().getModifiers().contains(STATIC)
+ ? ImmutableSet.<TypeElement>of()
+ : input.contributedBy().asSet();
+ }
+ })
+ .filter(in(ownedModuleTypes()))
+ .append(componentDescriptor().dependencies())
+ .append(componentDescriptor().executorDependency().asSet())
+ .toSet();
+ }
+
+ ImmutableSet<TypeElement> availableDependencies() {
+ return new ImmutableSet.Builder<TypeElement>()
+ .addAll(componentDescriptor().transitiveModuleTypes())
+ .addAll(componentDescriptor().dependencies())
+ .addAll(componentDescriptor().executorDependency().asSet())
+ .build();
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final Key.Factory keyFactory;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final ProductionBinding.Factory productionBindingFactory;
+
+ Factory(Elements elements,
+ InjectBindingRegistry injectBindingRegistry,
+ Key.Factory keyFactory,
+ ProvisionBinding.Factory provisionBindingFactory,
+ ProductionBinding.Factory productionBindingFactory) {
+ this.elements = elements;
+ this.injectBindingRegistry = injectBindingRegistry;
+ this.keyFactory = keyFactory;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.productionBindingFactory = productionBindingFactory;
+ }
+
+ BindingGraph create(ComponentDescriptor componentDescriptor) {
+ return create(Optional.<Resolver>absent(), componentDescriptor);
+ }
+
+ private BindingGraph create(
+ Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
+ ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder();
+
+ // binding for the component itself
+ TypeElement componentDefinitionType = componentDescriptor.componentDefinitionType();
+ explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDefinitionType));
+
+ // Collect Component dependencies.
+ Optional<AnnotationMirror> componentMirror =
+ getAnnotationMirror(componentDefinitionType, Component.class)
+ .or(getAnnotationMirror(componentDefinitionType, ProductionComponent.class));
+ ImmutableSet<TypeElement> componentDependencyTypes = componentMirror.isPresent()
+ ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror.get()))
+ : ImmutableSet.<TypeElement>of();
+ for (TypeElement componentDependency : componentDependencyTypes) {
+ explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDependency));
+ List<ExecutableElement> dependencyMethods =
+ ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
+ for (ExecutableElement method : dependencyMethods) {
+ // MembersInjection methods aren't "provided" explicitly, so ignore them.
+ if (isComponentContributionMethod(elements, method)) {
+ explicitBindingsBuilder.add(
+ componentDescriptor.kind().equals(PRODUCTION_COMPONENT)
+ && isComponentProductionMethod(elements, method)
+ ? productionBindingFactory.forComponentMethod(method)
+ : provisionBindingFactory.forComponentMethod(method));
+ }
+ }
+ }
+
+ // Bindings for subcomponent builders.
+ for (ComponentMethodDescriptor subcomponentMethodDescriptor :
+ Iterables.filter(
+ componentDescriptor.subcomponents().keySet(), isOfKind(SUBCOMPONENT_BUILDER))) {
+ explicitBindingsBuilder.add(
+ provisionBindingFactory.forSubcomponentBuilderMethod(
+ subcomponentMethodDescriptor.methodElement(),
+ componentDescriptor.componentDefinitionType()));
+ }
+
+ // Collect transitive module bindings.
+ for (ModuleDescriptor moduleDescriptor : componentDescriptor.transitiveModules()) {
+ for (ContributionBinding binding : moduleDescriptor.bindings()) {
+ explicitBindingsBuilder.add(binding);
+ }
+ }
+
+ Resolver requestResolver =
+ new Resolver(
+ parentResolver,
+ componentDescriptor,
+ explicitBindingsByKey(explicitBindingsBuilder.build()));
+ for (ComponentMethodDescriptor componentMethod : componentDescriptor.componentMethods()) {
+ Optional<DependencyRequest> componentMethodRequest = componentMethod.dependencyRequest();
+ if (componentMethodRequest.isPresent()) {
+ requestResolver.resolve(componentMethodRequest.get());
+ }
+ }
+
+ ImmutableMap.Builder<ExecutableElement, BindingGraph> subgraphsBuilder =
+ ImmutableMap.builder();
+ for (Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry :
+ componentDescriptor.subcomponents().entrySet()) {
+ subgraphsBuilder.put(
+ subcomponentEntry.getKey().methodElement(),
+ create(Optional.of(requestResolver), subcomponentEntry.getValue()));
+ }
+
+ for (ResolvedBindings resolvedBindings : requestResolver.getResolvedBindings().values()) {
+ verify(
+ resolvedBindings.owningComponent().equals(componentDescriptor),
+ "%s is not owned by %s",
+ resolvedBindings,
+ componentDescriptor);
+ }
+
+ return new AutoValue_BindingGraph(
+ componentDescriptor,
+ requestResolver.getResolvedBindings(),
+ subgraphsBuilder.build(),
+ requestResolver.getOwnedModules());
+ }
+
+ private <B extends ContributionBinding> ImmutableSetMultimap<Key, B> explicitBindingsByKey(
+ Iterable<? extends B> bindings) {
+ // Multimaps.index() doesn't do ImmutableSetMultimaps.
+ ImmutableSetMultimap.Builder<Key, B> builder = ImmutableSetMultimap.builder();
+ for (B binding : bindings) {
+ builder.put(binding.key(), binding);
+ }
+ return builder.build();
+ }
+
+ private final class Resolver {
+ final Optional<Resolver> parentResolver;
+ final ComponentDescriptor componentDescriptor;
+ final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings;
+ final ImmutableSet<ContributionBinding> explicitBindingsSet;
+ final Map<BindingKey, ResolvedBindings> resolvedBindings;
+ final Deque<BindingKey> cycleStack = new ArrayDeque<>();
+ final Cache<BindingKey, Boolean> dependsOnLocalMultibindingsCache =
+ CacheBuilder.newBuilder().<BindingKey, Boolean>build();
+
+ Resolver(
+ Optional<Resolver> parentResolver,
+ ComponentDescriptor componentDescriptor,
+ ImmutableSetMultimap<Key, ContributionBinding> explicitBindings) {
+ assert parentResolver != null;
+ this.parentResolver = parentResolver;
+ assert componentDescriptor != null;
+ this.componentDescriptor = componentDescriptor;
+ assert explicitBindings != null;
+ this.explicitBindings = explicitBindings;
+ this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values());
+ this.resolvedBindings = Maps.newLinkedHashMap();
+ }
+
+ /**
+ * Looks up the bindings associated with a given dependency request and returns them.
+ *
+ * <p>Requests for {@code Map<K, V>} for which there are only bindings for
+ * {@code Map<K, Provider<V>>} will resolve to a single implicit binding for the latter map
+ * (and similarly for {@link Producer}s).
+ *
+ * <p>If there are no explicit bindings for a contribution, looks for implicit
+ * {@link Inject @Inject}-annotated constructor types.
+ */
+ ResolvedBindings lookUpBindings(DependencyRequest request) {
+ BindingKey bindingKey = request.bindingKey();
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ // First, check for explicit keys (those from modules and components)
+ ImmutableSet<ContributionBinding> explicitBindingsForKey =
+ getExplicitBindings(bindingKey.key());
+
+ // If the key is Map<K, V>, get its implicit binding keys, which are either
+ // Map<K, Provider<V>> or Map<K, Producer<V>>, and grab their explicit bindings.
+ Optional<Key> mapProviderKey = keyFactory.implicitMapProviderKeyFrom(bindingKey.key());
+ ImmutableSet.Builder<ContributionBinding> explicitMapBindingsBuilder =
+ ImmutableSet.builder();
+ if (mapProviderKey.isPresent()) {
+ explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProviderKey.get()));
+ }
+
+ Optional<Key> mapProducerKey = keyFactory.implicitMapProducerKeyFrom(bindingKey.key());
+ if (mapProducerKey.isPresent()) {
+ explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProducerKey.get()));
+ }
+ ImmutableSet<ContributionBinding> explicitMapBindings =
+ explicitMapBindingsBuilder.build();
+
+ // If the key is Set<Produced<T>>, then we look up bindings by the alternate key Set<T>.
+ Optional<Key> setKeyFromProduced =
+ keyFactory.implicitSetKeyFromProduced(bindingKey.key());
+ ImmutableSet<ContributionBinding> explicitSetBindings =
+ setKeyFromProduced.isPresent()
+ ? getExplicitBindings(setKeyFromProduced.get())
+ : ImmutableSet.<ContributionBinding>of();
+
+ if (!explicitBindingsForKey.isEmpty() || !explicitSetBindings.isEmpty()) {
+ /* If there are any explicit bindings for this key, then combine those with any
+ * conflicting Map<K, Provider<V>> bindings and let the validator fail. */
+ ImmutableSetMultimap.Builder<ComponentDescriptor, ContributionBinding> bindings =
+ ImmutableSetMultimap.builder();
+ for (ContributionBinding binding :
+ union(explicitBindingsForKey, union(explicitSetBindings, explicitMapBindings))) {
+ bindings.put(getOwningComponent(request, binding), binding);
+ }
+ return ResolvedBindings.forContributionBindings(
+ bindingKey, componentDescriptor, bindings.build());
+ } else if (any(explicitMapBindings, Binding.Type.PRODUCTION)) {
+ /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but
+ * some explicit Map<K, Producer<V>> bindings, then this binding must have only the
+ * implicit dependency on Map<K, Producer<V>>. */
+ return ResolvedBindings.forContributionBindings(
+ bindingKey,
+ componentDescriptor,
+ productionBindingFactory.implicitMapOfProducerBinding(request));
+ } else if (any(explicitMapBindings, Binding.Type.PROVISION)) {
+ /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but
+ * some explicit Map<K, Provider<V>> bindings, then this binding must have only the
+ * implicit dependency on Map<K, Provider<V>>. */
+ return ResolvedBindings.forContributionBindings(
+ bindingKey,
+ componentDescriptor,
+ provisionBindingFactory.implicitMapOfProviderBinding(request));
+ } else {
+ /* If there are no explicit bindings at all, look for an implicit @Inject-constructed
+ * binding. */
+ Optional<ProvisionBinding> provisionBinding =
+ injectBindingRegistry.getOrFindProvisionBinding(bindingKey.key());
+ ComponentDescriptor owningComponent =
+ provisionBinding.isPresent()
+ && isResolvedInParent(request, provisionBinding.get())
+ && !shouldOwnParentBinding(request, provisionBinding.get())
+ ? getOwningResolver(provisionBinding.get()).get().componentDescriptor
+ : componentDescriptor;
+ return ResolvedBindings.forContributionBindings(
+ bindingKey,
+ componentDescriptor,
+ ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder()
+ .putAll(owningComponent, provisionBinding.asSet())
+ .build());
+ }
+
+ case MEMBERS_INJECTION:
+ // no explicit deps for members injection, so just look it up
+ return ResolvedBindings.forMembersInjectionBinding(
+ bindingKey, componentDescriptor, rollUpMembersInjectionBindings(bindingKey.key()));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * If {@code binding} should be owned by a parent component, resolves the binding in that
+ * component's resolver and returns that component. Otherwise returns the component for this
+ * resolver.
+ */
+ private ComponentDescriptor getOwningComponent(
+ DependencyRequest request, ContributionBinding binding) {
+ return isResolvedInParent(request, binding) && !shouldOwnParentBinding(request, binding)
+ ? getOwningResolver(binding).get().componentDescriptor
+ : componentDescriptor;
+ }
+
+ /**
+ * Returns {@code true} if {@code binding} is owned by a parent resolver. If so, calls
+ * {@link #resolve(DependencyRequest) resolve(request)} on that resolver.
+ */
+ private boolean isResolvedInParent(DependencyRequest request, ContributionBinding binding) {
+ Optional<Resolver> owningResolver = getOwningResolver(binding);
+ if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
+ owningResolver.get().resolve(request);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code binding}, which was previously resolved by a parent
+ * resolver, should be moved into this resolver's bindings for {@code request} because it is
+ * unscoped and {@linkplain #dependsOnLocalMultibindings(ResolvedBindings) depends on local
+ * multibindings}, or {@code false} if it can satisfy {@code request} as an inherited binding.
+ */
+ private boolean shouldOwnParentBinding(
+ DependencyRequest request, ContributionBinding binding) {
+ return !binding.scope().isPresent()
+ && dependsOnLocalMultibindings(
+ getPreviouslyResolvedBindings(request.bindingKey()).get());
+ }
+
+ private MembersInjectionBinding rollUpMembersInjectionBindings(Key key) {
+ MembersInjectionBinding membersInjectionBinding =
+ injectBindingRegistry.getOrFindMembersInjectionBinding(key);
+
+ if (membersInjectionBinding.parentInjectorRequest().isPresent()
+ && membersInjectionBinding.injectionStrategy().equals(INJECT_MEMBERS)) {
+ MembersInjectionBinding parentBinding =
+ rollUpMembersInjectionBindings(
+ membersInjectionBinding.parentInjectorRequest().get().key());
+ if (parentBinding.injectionStrategy().equals(NO_OP)) {
+ return membersInjectionBinding.withoutParentInjectorRequest();
+ }
+ }
+
+ return membersInjectionBinding;
+ }
+
+ private Optional<Resolver> getOwningResolver(ContributionBinding provisionBinding) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (requestResolver.explicitBindingsSet.contains(provisionBinding)) {
+ return Optional.of(requestResolver);
+ }
+ }
+
+ // look for scope separately. we do this for the case where @Singleton can appear twice
+ // in the † compatibility mode
+ Scope bindingScope = provisionBinding.scope();
+ if (bindingScope.isPresent()) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (bindingScope.equals(requestResolver.componentDescriptor.scope())) {
+ return Optional.of(requestResolver);
+ }
+ }
+ }
+ return Optional.absent();
+ }
+
+ /** Returns the resolver lineage from parent to child. */
+ private ImmutableList<Resolver> getResolverLineage() {
+ List<Resolver> resolverList = Lists.newArrayList();
+ for (Optional<Resolver> currentResolver = Optional.of(this);
+ currentResolver.isPresent();
+ currentResolver = currentResolver.get().parentResolver) {
+ resolverList.add(currentResolver.get());
+ }
+ return ImmutableList.copyOf(Lists.reverse(resolverList));
+ }
+
+ private ImmutableSet<ContributionBinding> getExplicitBindings(Key requestKey) {
+ ImmutableSet.Builder<ContributionBinding> explicitBindingsForKey = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ explicitBindingsForKey.addAll(resolver.explicitBindings.get(requestKey));
+ }
+ return explicitBindingsForKey.build();
+ }
+
+ private Optional<ResolvedBindings> getPreviouslyResolvedBindings(
+ final BindingKey bindingKey) {
+ Optional<ResolvedBindings> result = Optional.fromNullable(resolvedBindings.get(bindingKey));
+ if (result.isPresent()) {
+ return result;
+ } else if (parentResolver.isPresent()) {
+ return parentResolver.get().getPreviouslyResolvedBindings(bindingKey);
+ } else {
+ return Optional.absent();
+ }
+ }
+
+ void resolve(DependencyRequest request) {
+ BindingKey bindingKey = request.bindingKey();
+
+ // If we find a cycle, stop resolving. The original request will add it with all of the
+ // other resolved deps.
+ if (cycleStack.contains(bindingKey)) {
+ return;
+ }
+
+ // If the binding was previously resolved in this (sub)component, don't resolve it again.
+ if (resolvedBindings.containsKey(bindingKey)) {
+ return;
+ }
+
+ // If the binding was previously resolved in a supercomponent, then test to see if it
+ // depends on multibindings with contributions from this subcomponent. If it does, then we
+ // have to resolve it in this subcomponent so that it sees the local contributions. If it
+ // does not, then we can stop resolving it in this subcomponent and rely on the
+ // supercomponent resolution.
+ Optional<ResolvedBindings> bindingsPreviouslyResolvedInParent =
+ getPreviouslyResolvedBindings(bindingKey);
+ if (bindingsPreviouslyResolvedInParent.isPresent()
+ && !dependsOnLocalMultibindings(bindingsPreviouslyResolvedInParent.get())) {
+ return;
+ }
+
+ cycleStack.push(bindingKey);
+ try {
+ ResolvedBindings bindings = lookUpBindings(request);
+ for (Binding binding : bindings.ownedBindings()) {
+ for (DependencyRequest dependency : binding.implicitDependencies()) {
+ resolve(dependency);
+ }
+ }
+ resolvedBindings.put(bindingKey, bindings);
+ } finally {
+ cycleStack.pop();
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code previouslyResolvedBindings} is multibindings with
+ * contributions declared within this (sub)component's modules, or if any of its unscoped
+ * provision-dependencies depend on such local multibindings.
+ *
+ * <p>We don't care about scoped dependencies or production bindings because they will never
+ * depend on multibindings with contributions from subcomponents.
+ */
+ private boolean dependsOnLocalMultibindings(ResolvedBindings previouslyResolvedBindings) {
+ return dependsOnLocalMultibindings(previouslyResolvedBindings, new HashSet<BindingKey>());
+ }
+
+ private boolean dependsOnLocalMultibindings(
+ final ResolvedBindings previouslyResolvedBindings, final Set<BindingKey> cycleChecker) {
+ // Don't recur infinitely if there are valid cycles in the dependency graph.
+ if (!cycleChecker.add(previouslyResolvedBindings.bindingKey())) {
+ return false;
+ }
+ try {
+ return dependsOnLocalMultibindingsCache.get(
+ previouslyResolvedBindings.bindingKey(),
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ if (previouslyResolvedBindings.isMultibindings()
+ && hasLocalContributions(previouslyResolvedBindings)) {
+ return true;
+ }
+
+ for (Binding binding : previouslyResolvedBindings.bindings()) {
+ if (!binding.scope().isPresent()
+ && !binding.bindingType().equals(Type.PRODUCTION)) {
+ for (DependencyRequest dependency : binding.implicitDependencies()) {
+ if (dependsOnLocalMultibindings(
+ getPreviouslyResolvedBindings(dependency.bindingKey()).get(),
+ cycleChecker)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ });
+ } catch (ExecutionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private boolean hasLocalContributions(ResolvedBindings resolvedBindings) {
+ return !explicitBindings.get(resolvedBindings.bindingKey().key()).isEmpty();
+ }
+
+ ImmutableMap<BindingKey, ResolvedBindings> getResolvedBindings() {
+ ImmutableMap.Builder<BindingKey, ResolvedBindings> resolvedBindingsBuilder =
+ ImmutableMap.builder();
+ resolvedBindingsBuilder.putAll(resolvedBindings);
+ if (parentResolver.isPresent()) {
+ Collection<ResolvedBindings> bindingsResolvedInParent =
+ Maps.difference(parentResolver.get().getResolvedBindings(), resolvedBindings)
+ .entriesOnlyOnLeft()
+ .values();
+ for (ResolvedBindings resolvedInParent : bindingsResolvedInParent) {
+ resolvedBindingsBuilder.put(
+ resolvedInParent.bindingKey(),
+ resolvedInParent.asInheritedIn(componentDescriptor));
+ }
+ }
+ return resolvedBindingsBuilder.build();
+ }
+
+ ImmutableSet<ModuleDescriptor> getInheritedModules() {
+ return parentResolver.isPresent()
+ ? Sets.union(
+ parentResolver.get().getInheritedModules(),
+ parentResolver.get().componentDescriptor.transitiveModules())
+ .immutableCopy()
+ : ImmutableSet.<ModuleDescriptor>of();
+ }
+
+ ImmutableSet<ModuleDescriptor> getOwnedModules() {
+ return Sets.difference(componentDescriptor.transitiveModules(), getInheritedModules())
+ .immutableCopy();
+ }
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java
new file mode 100644
index 0000000..f8010c3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+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.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MapKey;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ContributionBinding.ContributionType;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+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.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+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.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.all;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Iterables.indexOf;
+import static com.google.common.collect.Iterables.skip;
+import static com.google.common.collect.Maps.filterKeys;
+import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor.isOfKind;
+import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind.SUBCOMPONENT;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByAnnotationType;
+import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByMapKey;
+import static dagger.internal.codegen.ErrorMessages.DUPLICATE_SIZE_LIMIT;
+import static dagger.internal.codegen.ErrorMessages.INDENT;
+import static dagger.internal.codegen.ErrorMessages.MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_PROVIDER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.REQUIRES_PROVIDER_OR_PRODUCER_FORMAT;
+import static dagger.internal.codegen.ErrorMessages.duplicateMapKeysError;
+import static dagger.internal.codegen.ErrorMessages.inconsistentMapKeyAnnotationsError;
+import static dagger.internal.codegen.ErrorMessages.nullableToNonNullable;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static dagger.internal.codegen.Util.getKeyTypeOfMap;
+import static dagger.internal.codegen.Util.getProvidedValueTypeOfMap;
+import static dagger.internal.codegen.Util.getValueTypeOfMap;
+import static dagger.internal.codegen.Util.isMapWithNonProvidedValues;
+import static dagger.internal.codegen.Util.isMapWithProvidedValues;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+public class BindingGraphValidator {
+
+ private final Types types;
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final ValidationType scopeCycleValidationType;
+ private final Diagnostic.Kind nullableValidationType;
+ private final ContributionBindingFormatter contributionBindingFormatter;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final DependencyRequestFormatter dependencyRequestFormatter;
+ private final KeyFormatter keyFormatter;
+
+ BindingGraphValidator(
+ Types types,
+ InjectBindingRegistry injectBindingRegistry,
+ ValidationType scopeCycleValidationType,
+ Diagnostic.Kind nullableValidationType,
+ ContributionBindingFormatter contributionBindingFormatter,
+ MethodSignatureFormatter methodSignatureFormatter,
+ DependencyRequestFormatter dependencyRequestFormatter,
+ KeyFormatter keyFormatter) {
+ this.types = types;
+ this.injectBindingRegistry = injectBindingRegistry;
+ this.scopeCycleValidationType = scopeCycleValidationType;
+ this.nullableValidationType = nullableValidationType;
+ this.contributionBindingFormatter = contributionBindingFormatter;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.dependencyRequestFormatter = dependencyRequestFormatter;
+ this.keyFormatter = keyFormatter;
+ }
+
+ private class Validation {
+ final BindingGraph topLevelGraph;
+ final BindingGraph subject;
+ final ValidationReport.Builder<TypeElement> reportBuilder;
+
+ Validation(BindingGraph topLevelGraph, BindingGraph subject) {
+ this.topLevelGraph = topLevelGraph;
+ this.subject = subject;
+ this.reportBuilder =
+ ValidationReport.about(subject.componentDescriptor().componentDefinitionType());
+ }
+
+ Validation(BindingGraph topLevelGraph) {
+ this(topLevelGraph, topLevelGraph);
+ }
+
+ ValidationReport<TypeElement> buildReport() {
+ return reportBuilder.build();
+ }
+
+ void validateSubgraph() {
+ validateComponentScope();
+ validateDependencyScopes();
+ validateComponentHierarchy();
+ validateBuilders();
+
+ for (ComponentMethodDescriptor componentMethod :
+ subject.componentDescriptor().componentMethods()) {
+ Optional<DependencyRequest> entryPoint = componentMethod.dependencyRequest();
+ if (entryPoint.isPresent()) {
+ traverseRequest(
+ entryPoint.get(),
+ new ArrayDeque<ResolvedRequest>(),
+ new LinkedHashSet<BindingKey>(),
+ subject,
+ new HashSet<DependencyRequest>());
+ }
+ }
+
+ for (Map.Entry<ComponentMethodDescriptor, ComponentDescriptor> entry :
+ filterKeys(subject.componentDescriptor().subcomponents(), isOfKind(SUBCOMPONENT))
+ .entrySet()) {
+ validateSubcomponentFactoryMethod(
+ entry.getKey().methodElement(), entry.getValue().componentDefinitionType());
+ }
+
+ for (BindingGraph subgraph : subject.subgraphs().values()) {
+ Validation subgraphValidation =
+ new Validation(topLevelGraph, subgraph);
+ subgraphValidation.validateSubgraph();
+ reportBuilder.addSubreport(subgraphValidation.buildReport());
+ }
+ }
+
+ private void validateSubcomponentFactoryMethod(
+ ExecutableElement factoryMethod, TypeElement subcomponentType) {
+ BindingGraph subgraph = subject.subgraphs().get(factoryMethod);
+ FluentIterable<TypeElement> missingModules =
+ FluentIterable.from(subgraph.componentRequirements())
+ .filter(not(in(subgraphFactoryMethodParameters(factoryMethod))))
+ .filter(
+ new Predicate<TypeElement>() {
+ @Override
+ public boolean apply(TypeElement moduleType) {
+ return !componentCanMakeNewInstances(moduleType);
+ }
+ });
+ if (!missingModules.isEmpty()) {
+ reportBuilder.addError(
+ String.format(
+ "%s requires modules which have no visible default constructors. "
+ + "Add the following modules as parameters to this method: %s",
+ subcomponentType.getQualifiedName(),
+ Joiner.on(", ").join(missingModules.toSet())),
+ factoryMethod);
+ }
+ }
+
+ private ImmutableSet<TypeElement> subgraphFactoryMethodParameters(
+ ExecutableElement factoryMethod) {
+ DeclaredType componentType =
+ asDeclared(subject.componentDescriptor().componentDefinitionType().asType());
+ ExecutableType factoryMethodType =
+ asExecutable(types.asMemberOf(componentType, factoryMethod));
+ return asTypeElements(factoryMethodType.getParameterTypes());
+ }
+
+ /**
+ * Traverse the resolved dependency requests, validating resolved bindings, and reporting any
+ * cycles found.
+ *
+ * @param request the current dependency request
+ * @param bindingPath the dependency request path from the parent of {@code request} at the head
+ * up to the root dependency request from the component method at the tail
+ * @param keysInPath the binding keys corresponding to the dependency requests in
+ * {@code bindingPath}, but in reverse order: the first element is the binding key from the
+ * component method
+ * @param resolvedRequests the requests that have already been resolved, so we can avoid
+ * traversing that part of the graph again
+ */
+ // TODO(dpb): It might be simpler to invert bindingPath's order.
+ private void traverseRequest(
+ DependencyRequest request,
+ Deque<ResolvedRequest> bindingPath,
+ LinkedHashSet<BindingKey> keysInPath,
+ BindingGraph graph,
+ Set<DependencyRequest> resolvedRequests) {
+ verify(bindingPath.size() == keysInPath.size(),
+ "mismatched path vs keys -- (%s vs %s)", bindingPath, keysInPath);
+ BindingKey requestKey = request.bindingKey();
+ if (keysInPath.contains(requestKey)) {
+ reportCycle(
+ // Invert bindingPath to match keysInPath's order
+ ImmutableList.copyOf(bindingPath).reverse(),
+ request,
+ indexOf(keysInPath, equalTo(requestKey)));
+ return;
+ }
+
+ // If request has already been resolved, avoid re-traversing the binding path.
+ if (resolvedRequests.add(request)) {
+ ResolvedRequest resolvedRequest = ResolvedRequest.create(request, graph);
+ bindingPath.push(resolvedRequest);
+ keysInPath.add(requestKey);
+ validateResolvedBinding(bindingPath, resolvedRequest.binding());
+
+ for (Binding binding : resolvedRequest.binding().bindings()) {
+ for (DependencyRequest nextRequest : binding.implicitDependencies()) {
+ traverseRequest(nextRequest, bindingPath, keysInPath, graph, resolvedRequests);
+ }
+ }
+ bindingPath.poll();
+ keysInPath.remove(requestKey);
+ }
+ }
+
+ /**
+ * Validates that the set of bindings resolved is consistent with the type of the binding, and
+ * returns true if the bindings are valid.
+ */
+ private boolean validateResolvedBinding(
+ Deque<ResolvedRequest> path, ResolvedBindings resolvedBinding) {
+ if (resolvedBinding.bindings().isEmpty()) {
+ reportMissingBinding(path);
+ return false;
+ }
+
+ switch (resolvedBinding.bindingKey().kind()) {
+ case CONTRIBUTION:
+ ImmutableSet<ContributionBinding> contributionBindings =
+ resolvedBinding.contributionBindings();
+ if (any(contributionBindings, Binding.Type.MEMBERS_INJECTION)) {
+ throw new IllegalArgumentException(
+ "contribution binding keys should never have members injection bindings");
+ }
+ if (!validateNullability(path.peek().request(), contributionBindings)) {
+ return false;
+ }
+ if (any(contributionBindings, Binding.Type.PRODUCTION)
+ && doesPathRequireProvisionOnly(path)) {
+ reportProviderMayNotDependOnProducer(path);
+ return false;
+ }
+ if (contributionBindings.size() <= 1) {
+ return true;
+ }
+ ImmutableListMultimap<ContributionType, ContributionBinding> contributionsByType =
+ ContributionBinding.contributionTypesFor(contributionBindings);
+ if (contributionsByType.keySet().size() > 1) {
+ reportMultipleBindingTypes(path);
+ return false;
+ }
+ switch (getOnlyElement(contributionsByType.keySet())) {
+ case UNIQUE:
+ reportDuplicateBindings(path);
+ return false;
+ case MAP:
+ boolean duplicateMapKeys = hasDuplicateMapKeys(path, contributionBindings);
+ boolean inconsistentMapKeyAnnotationTypes =
+ hasInconsistentMapKeyAnnotationTypes(path, contributionBindings);
+ return !duplicateMapKeys && !inconsistentMapKeyAnnotationTypes;
+ case SET:
+ break;
+ default:
+ throw new AssertionError();
+ }
+ break;
+ case MEMBERS_INJECTION:
+ if (!all(resolvedBinding.bindings(), Binding.Type.MEMBERS_INJECTION)) {
+ throw new IllegalArgumentException(
+ "members injection binding keys should never have contribution bindings");
+ }
+ if (resolvedBinding.bindings().size() > 1) {
+ reportDuplicateBindings(path);
+ return false;
+ }
+ return validateMembersInjectionBinding(getOnlyElement(resolvedBinding.bindings()), path);
+ default:
+ throw new AssertionError();
+ }
+ return true;
+ }
+
+ /** Ensures that if the request isn't nullable, then each contribution is also not nullable. */
+ private boolean validateNullability(
+ DependencyRequest request, Set<ContributionBinding> bindings) {
+ if (request.isNullable()) {
+ return true;
+ }
+
+ // Note: the method signature will include the @Nullable in it!
+ /* TODO(sameb): Sometimes javac doesn't include the Element in its output.
+ * (Maybe this happens if the code was already compiled before this point?)
+ * ... we manually print out the request in that case, otherwise the error
+ * message is kind of useless. */
+ String typeName = TypeNames.forTypeMirror(request.key().type()).toString();
+
+ boolean valid = true;
+ for (ContributionBinding binding : bindings) {
+ if (binding.nullableType().isPresent()) {
+ reportBuilder.addItem(
+ nullableToNonNullable(typeName, contributionBindingFormatter.format(binding))
+ + "\n at: "
+ + dependencyRequestFormatter.format(request),
+ nullableValidationType,
+ request.requestElement());
+ valid = false;
+ }
+ }
+ return valid;
+ }
+
+ /**
+ * Returns {@code true} (and reports errors) if {@code mapBindings} has more than one binding
+ * for the same map key.
+ */
+ private boolean hasDuplicateMapKeys(
+ Deque<ResolvedRequest> path, Set<ContributionBinding> mapBindings) {
+ boolean hasDuplicateMapKeys = false;
+ for (Collection<ContributionBinding> mapBindingsForMapKey :
+ indexMapBindingsByMapKey(mapBindings).asMap().values()) {
+ if (mapBindingsForMapKey.size() > 1) {
+ hasDuplicateMapKeys = true;
+ reportDuplicateMapKeys(path, mapBindingsForMapKey);
+ }
+ }
+ return hasDuplicateMapKeys;
+ }
+
+ /**
+ * Returns {@code true} (and reports errors) if {@code mapBindings} uses more than one
+ * {@link MapKey} annotation type.
+ */
+ private boolean hasInconsistentMapKeyAnnotationTypes(
+ Deque<ResolvedRequest> path, Set<ContributionBinding> contributionBindings) {
+ ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ mapBindingsByAnnotationType = indexMapBindingsByAnnotationType(contributionBindings);
+ if (mapBindingsByAnnotationType.keySet().size() > 1) {
+ reportInconsistentMapKeyAnnotations(path, mapBindingsByAnnotationType);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Validates a members injection binding, returning false (and reporting the error) if it wasn't
+ * valid.
+ */
+ private boolean validateMembersInjectionBinding(
+ Binding binding, final Deque<ResolvedRequest> path) {
+ return binding
+ .key()
+ .type()
+ .accept(
+ new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override
+ protected Boolean defaultAction(TypeMirror e, Void p) {
+ reportBuilder.addError(
+ "Invalid members injection request.", path.peek().request().requestElement());
+ return false;
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType type, Void ignored) {
+ // 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. If the arg was an array, validate the type
+ // of the array.
+ for (TypeMirror arg : type.getTypeArguments()) {
+ boolean declared;
+ switch (arg.getKind()) {
+ case ARRAY:
+ declared =
+ MoreTypes.asArray(arg)
+ .getComponentType()
+ .accept(
+ new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override
+ protected Boolean defaultAction(TypeMirror e, Void p) {
+ return false;
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, Void p) {
+ for (TypeMirror arg : t.getTypeArguments()) {
+ if (!arg.accept(this, null)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Boolean visitArray(ArrayType t, Void p) {
+ return t.getComponentType().accept(this, null);
+ }
+
+ @Override
+ public Boolean visitPrimitive(PrimitiveType t, Void p) {
+ return true;
+ }
+ },
+ null);
+ break;
+ case DECLARED:
+ declared = true;
+ break;
+ default:
+ declared = false;
+ }
+ if (!declared) {
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ reportBuilder.addError(
+ String.format(
+ MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE,
+ arg.toString(),
+ type.toString(),
+ Joiner.on('\n').join(printableDependencyPath)),
+ path.peek().request().requestElement());
+ return false;
+ }
+ }
+
+ TypeElement element = MoreElements.asType(type.asElement());
+ // 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.)
+ if (!MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
+ && types.isSameType(types.erasure(element.asType()), type)) {
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ reportBuilder.addError(
+ String.format(
+ ErrorMessages.MEMBERS_INJECTION_WITH_RAW_TYPE,
+ type.toString(),
+ Joiner.on('\n').join(printableDependencyPath)),
+ path.peek().request().requestElement());
+ return false;
+ }
+
+ return true; // valid
+ }
+ },
+ null);
+ }
+
+ /**
+ * Validates that component dependencies do not form a cycle.
+ */
+ private void validateComponentHierarchy() {
+ ComponentDescriptor descriptor = subject.componentDescriptor();
+ TypeElement componentType = descriptor.componentDefinitionType();
+ validateComponentHierarchy(componentType, componentType, new ArrayDeque<TypeElement>());
+ }
+
+ /**
+ * Recursive method to validate that component dependencies do not form a cycle.
+ */
+ private void validateComponentHierarchy(
+ TypeElement rootComponent,
+ TypeElement componentType,
+ Deque<TypeElement> componentStack) {
+
+ if (componentStack.contains(componentType)) {
+ // Current component has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(rootComponent.getQualifiedName());
+ message.append(" contains a cycle in its component dependencies:\n");
+ componentStack.push(componentType);
+ appendIndentedComponentsList(message, componentStack);
+ componentStack.pop();
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ rootComponent, getAnnotationMirror(rootComponent, Component.class).get());
+ } else {
+ Optional<AnnotationMirror> componentAnnotation =
+ getAnnotationMirror(componentType, Component.class);
+ if (componentAnnotation.isPresent()) {
+ componentStack.push(componentType);
+
+ ImmutableSet<TypeElement> dependencies =
+ MoreTypes.asTypeElements(getComponentDependencies(componentAnnotation.get()));
+ for (TypeElement dependency : dependencies) {
+ validateComponentHierarchy(rootComponent, dependency, componentStack);
+ }
+
+ componentStack.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 descriptor = subject.componentDescriptor();
+ Scope scope = descriptor.scope();
+ ImmutableSet<TypeElement> scopedDependencies = scopedTypesIn(descriptor.dependencies());
+ if (scope.isPresent()) {
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (scopeCycleValidationType.diagnosticKind().isPresent()
+ && scope.isSingleton()) {
+ // 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);
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ }
+ } else if (scopedDependencies.size() > 1) {
+ // Scoped components may depend on at most one scoped component.
+ StringBuilder message = new StringBuilder(scope.getReadableSource())
+ .append(' ')
+ .append(descriptor.componentDefinitionType().getQualifiedName())
+ .append(" depends on more than one scoped component:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportBuilder.addError(
+ message.toString(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ } else {
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (!scopeCycleValidationType.equals(ValidationType.NONE)) {
+ validateScopeHierarchy(descriptor.componentDefinitionType(),
+ descriptor.componentDefinitionType(),
+ new ArrayDeque<Scope>(),
+ new ArrayDeque<TypeElement>());
+ }
+ }
+ } else {
+ // Scopeless components may not depend on scoped components.
+ if (!scopedDependencies.isEmpty()) {
+ StringBuilder message =
+ new StringBuilder(descriptor.componentDefinitionType().getQualifiedName())
+ .append(" (unscoped) cannot depend on scoped components:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportBuilder.addError(
+ message.toString(),
+ descriptor.componentDefinitionType(),
+ descriptor.componentAnnotation());
+ }
+ }
+ }
+
+ private void validateBuilders() {
+ ComponentDescriptor componentDesc = subject.componentDescriptor();
+ if (!componentDesc.builderSpec().isPresent()) {
+ // If no builder, nothing to validate.
+ return;
+ }
+
+ Set<TypeElement> availableDependencies = subject.availableDependencies();
+ Set<TypeElement> requiredDependencies =
+ Sets.filter(
+ availableDependencies,
+ new Predicate<TypeElement>() {
+ @Override
+ public boolean apply(TypeElement input) {
+ return !Util.componentCanMakeNewInstances(input);
+ }
+ });
+ final BuilderSpec spec = componentDesc.builderSpec().get();
+ Map<TypeElement, ExecutableElement> allSetters = spec.methodMap();
+
+ ErrorMessages.ComponentBuilderMessages msgs =
+ ErrorMessages.builderMsgsFor(subject.componentDescriptor().kind());
+ Set<TypeElement> extraSetters = Sets.difference(allSetters.keySet(), availableDependencies);
+ if (!extraSetters.isEmpty()) {
+ Collection<ExecutableElement> excessMethods =
+ Maps.filterKeys(allSetters, Predicates.in(extraSetters)).values();
+ Iterable<String> formatted = FluentIterable.from(excessMethods).transform(
+ new Function<ExecutableElement, String>() {
+ @Override public String apply(ExecutableElement input) {
+ return methodSignatureFormatter.format(input,
+ Optional.of(MoreTypes.asDeclared(spec.builderDefinitionType().asType())));
+ }});
+ reportBuilder.addError(
+ String.format(msgs.extraSetters(), formatted), spec.builderDefinitionType());
+ }
+
+ Set<TypeElement> missingSetters = Sets.difference(requiredDependencies, allSetters.keySet());
+ if (!missingSetters.isEmpty()) {
+ reportBuilder.addError(
+ String.format(msgs.missingSetters(), missingSetters), spec.builderDefinitionType());
+ }
+ }
+
+ /**
+ * 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 #validateComponentHierarchy()}.
+ */
+ private void validateScopeHierarchy(TypeElement rootComponent,
+ TypeElement componentType,
+ Deque<Scope> scopeStack,
+ Deque<TypeElement> scopedDependencyStack) {
+ Scope scope = Scope.scopeOf(componentType);
+ if (scope.isPresent()) {
+ if (scopeStack.contains(scope)) {
+ scopedDependencyStack.push(componentType);
+ // Current scope has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(rootComponent.getQualifiedName());
+ message.append(" depends on scoped components in a non-hierarchical scope ordering:\n");
+ appendIndentedComponentsList(message, scopedDependencyStack);
+ if (scopeCycleValidationType.diagnosticKind().isPresent()) {
+ reportBuilder.addItem(message.toString(),
+ scopeCycleValidationType.diagnosticKind().get(),
+ rootComponent, getAnnotationMirror(rootComponent, Component.class).get());
+ }
+ scopedDependencyStack.pop();
+ } else {
+ Optional<AnnotationMirror> componentAnnotation =
+ getAnnotationMirror(componentType, Component.class);
+ if (componentAnnotation.isPresent()) {
+ ImmutableSet<TypeElement> scopedDependencies = scopedTypesIn(
+ MoreTypes.asTypeElements(getComponentDependencies(componentAnnotation.get())));
+ if (scopedDependencies.size() == 1) {
+ // empty can be ignored (base-case), and > 1 is a different error reported separately.
+ scopeStack.push(scope);
+ scopedDependencyStack.push(componentType);
+ validateScopeHierarchy(rootComponent, getOnlyElement(scopedDependencies),
+ scopeStack, scopedDependencyStack);
+ scopedDependencyStack.pop();
+ scopeStack.pop();
+ }
+ } // else: we skip component dependencies which are not components
+ }
+ }
+ }
+
+ /**
+ * Validates that the scope (if any) of this component are compatible with the scopes of the
+ * bindings available in this component
+ */
+ void validateComponentScope() {
+ ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings = subject.resolvedBindings();
+ Scope componentScope = subject.componentDescriptor().scope();
+ ImmutableSet.Builder<String> incompatiblyScopedMethodsBuilder = ImmutableSet.builder();
+ for (ResolvedBindings bindings : resolvedBindings.values()) {
+ if (bindings.bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)) {
+ for (ContributionBinding contributionBinding : bindings.ownedContributionBindings()) {
+ Scope bindingScope = contributionBinding.scope();
+ if (bindingScope.isPresent() && !bindingScope.equals(componentScope)) {
+ // Scoped components cannot reference bindings to @Provides methods or @Inject
+ // types decorated by a different scope annotation. Unscoped components cannot
+ // reference to scoped @Provides methods or @Inject types decorated by any
+ // scope annotation.
+ switch (contributionBinding.bindingKind()) {
+ case PROVISION:
+ ExecutableElement provisionMethod =
+ MoreElements.asExecutable(contributionBinding.bindingElement());
+ incompatiblyScopedMethodsBuilder.add(
+ methodSignatureFormatter.format(provisionMethod));
+ break;
+ case INJECTION:
+ incompatiblyScopedMethodsBuilder.add(
+ bindingScope.getReadableSource()
+ + " class "
+ + contributionBinding.bindingTypeElement().getQualifiedName());
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+ }
+ ImmutableSet<String> incompatiblyScopedMethods = incompatiblyScopedMethodsBuilder.build();
+ if (!incompatiblyScopedMethods.isEmpty()) {
+ TypeElement componentType = subject.componentDescriptor().componentDefinitionType();
+ StringBuilder message = new StringBuilder(componentType.getQualifiedName());
+ if (componentScope.isPresent()) {
+ message.append(" scoped with ");
+ message.append(componentScope.getReadableSource());
+ message.append(" may not reference bindings with different scopes:\n");
+ } else {
+ message.append(" (unscoped) may not reference scoped bindings:\n");
+ }
+ for (String method : incompatiblyScopedMethods) {
+ message.append(ErrorMessages.INDENT).append(method).append("\n");
+ }
+ reportBuilder.addError(
+ message.toString(), componentType, subject.componentDescriptor().componentAnnotation());
+ }
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportProviderMayNotDependOnProducer(Deque<ResolvedRequest> path) {
+ StringBuilder errorMessage = new StringBuilder();
+ if (path.size() == 1) {
+ new Formatter(errorMessage)
+ .format(
+ ErrorMessages.PROVIDER_ENTRY_POINT_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT,
+ formatRootRequestKey(path));
+ } else {
+ ImmutableSet<? extends Binding> dependentProvisions =
+ provisionsDependingOnLatestRequest(path);
+ // TODO(beder): Consider displaying all dependent provisions in the error message. If we do
+ // that, should we display all productions that depend on them also?
+ new Formatter(errorMessage).format(ErrorMessages.PROVIDER_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT,
+ keyFormatter.format(dependentProvisions.iterator().next().key()));
+ }
+ reportBuilder.addError(errorMessage.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportMissingBinding(Deque<ResolvedRequest> path) {
+ Key key = path.peek().request().key();
+ BindingKey bindingKey = path.peek().request().bindingKey();
+ boolean requiresContributionMethod = !key.isValidImplicitProvisionKey(types);
+ boolean requiresProvision = doesPathRequireProvisionOnly(path);
+ StringBuilder errorMessage = new StringBuilder();
+ String requiresErrorMessageFormat = requiresContributionMethod
+ ? requiresProvision
+ ? REQUIRES_PROVIDER_FORMAT
+ : REQUIRES_PROVIDER_OR_PRODUCER_FORMAT
+ : requiresProvision
+ ? REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT
+ : REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT;
+ errorMessage.append(String.format(requiresErrorMessageFormat, keyFormatter.format(key)));
+ if (key.isValidMembersInjectionKey()
+ && !injectBindingRegistry.getOrFindMembersInjectionBinding(key).injectionSites()
+ .isEmpty()) {
+ errorMessage.append(" ").append(ErrorMessages.MEMBERS_INJECTION_DOES_NOT_IMPLY_PROVISION);
+ }
+ ImmutableList<String> printableDependencyPath =
+ FluentIterable.from(path)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .transform(dependencyRequestFormatter)
+ .filter(Predicates.not(Predicates.equalTo("")))
+ .toList()
+ .reverse();
+ for (String dependency :
+ printableDependencyPath.subList(1, printableDependencyPath.size())) {
+ errorMessage.append('\n').append(dependency);
+ }
+ for (String suggestion : MissingBindingSuggestions.forKey(topLevelGraph, bindingKey)) {
+ errorMessage.append('\n').append(suggestion);
+ }
+ reportBuilder.addError(errorMessage.toString(), path.getLast().request().requestElement());
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportDuplicateBindings(Deque<ResolvedRequest> path) {
+ ResolvedBindings resolvedBinding = path.peek().binding();
+ StringBuilder builder = new StringBuilder();
+ new Formatter(builder)
+ .format(ErrorMessages.DUPLICATE_BINDINGS_FOR_KEY_FORMAT, formatRootRequestKey(path));
+ for (ContributionBinding binding :
+ Iterables.limit(resolvedBinding.contributionBindings(), DUPLICATE_SIZE_LIMIT)) {
+ builder.append('\n').append(INDENT).append(contributionBindingFormatter.format(binding));
+ }
+ int numberOfOtherBindings =
+ resolvedBinding.contributionBindings().size() - DUPLICATE_SIZE_LIMIT;
+ if (numberOfOtherBindings > 0) {
+ builder.append('\n').append(INDENT)
+ .append("and ").append(numberOfOtherBindings).append(" other");
+ }
+ if (numberOfOtherBindings > 1) {
+ builder.append('s');
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ @SuppressWarnings("resource") // Appendable is a StringBuilder.
+ private void reportMultipleBindingTypes(Deque<ResolvedRequest> path) {
+ ResolvedBindings resolvedBinding = path.peek().binding();
+ StringBuilder builder = new StringBuilder();
+ new Formatter(builder)
+ .format(ErrorMessages.MULTIPLE_BINDING_TYPES_FOR_KEY_FORMAT, formatRootRequestKey(path));
+ ImmutableListMultimap<ContributionType, ContributionBinding> bindingsByType =
+ ContributionBinding.contributionTypesFor(resolvedBinding.contributionBindings());
+ for (ContributionType type :
+ Ordering.natural().immutableSortedCopy(bindingsByType.keySet())) {
+ builder.append(INDENT);
+ builder.append(formatBindingType(type));
+ builder.append(" bindings:\n");
+ for (ContributionBinding binding : bindingsByType.get(type)) {
+ builder
+ .append(INDENT)
+ .append(INDENT)
+ .append(contributionBindingFormatter.format(binding))
+ .append('\n');
+ }
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportDuplicateMapKeys(
+ Deque<ResolvedRequest> path, Collection<ContributionBinding> mapBindings) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(duplicateMapKeysError(formatRootRequestKey(path)));
+ appendBindings(builder, mapBindings, 1);
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ private void reportInconsistentMapKeyAnnotations(
+ Deque<ResolvedRequest> path,
+ Multimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ mapBindingsByAnnotationType) {
+ StringBuilder builder =
+ new StringBuilder(inconsistentMapKeyAnnotationsError(formatRootRequestKey(path)));
+ for (Map.Entry<Equivalence.Wrapper<DeclaredType>, Collection<ContributionBinding>> entry :
+ mapBindingsByAnnotationType.asMap().entrySet()) {
+ DeclaredType annotationType = entry.getKey().get();
+ Collection<ContributionBinding> bindings = entry.getValue();
+
+ builder
+ .append('\n')
+ .append(INDENT)
+ .append(annotationType)
+ .append(':');
+
+ appendBindings(builder, bindings, 2);
+ }
+ reportBuilder.addError(builder.toString(), path.getLast().request().requestElement());
+ }
+
+ /**
+ * Reports a cycle in the binding path.
+ *
+ * @param bindingPath the binding path, starting with the component provision dependency, and
+ * ending with the binding that depends on {@code request}
+ * @param request the request that would have been added to the binding path if its
+ * {@linkplain DependencyRequest#bindingKey() binding key} wasn't already in it
+ * @param indexOfDuplicatedKey the index of the dependency request in {@code bindingPath} whose
+ * {@linkplain DependencyRequest#bindingKey() binding key} matches {@code request}'s
+ */
+ private void reportCycle(
+ Iterable<ResolvedRequest> bindingPath,
+ DependencyRequest request,
+ int indexOfDuplicatedKey) {
+ ImmutableList<DependencyRequest> requestPath =
+ FluentIterable.from(bindingPath)
+ .transform(REQUEST_FROM_RESOLVED_REQUEST)
+ .append(request)
+ .toList();
+ Element rootRequestElement = requestPath.get(0).requestElement();
+ ImmutableList<DependencyRequest> cycle =
+ requestPath.subList(indexOfDuplicatedKey, requestPath.size());
+ Diagnostic.Kind kind = cycleHasProviderOrLazy(cycle) ? WARNING : ERROR;
+ if (kind == WARNING
+ && (suppressCycleWarnings(rootRequestElement)
+ || suppressCycleWarnings(rootRequestElement.getEnclosingElement())
+ || suppressCycleWarnings(cycle))) {
+ return;
+ }
+ // TODO(cgruber): Provide a hint for the start and end of the cycle.
+ TypeElement componentType = MoreElements.asType(rootRequestElement.getEnclosingElement());
+ reportBuilder.addItem(
+ String.format(
+ ErrorMessages.CONTAINS_DEPENDENCY_CYCLE_FORMAT,
+ componentType.getQualifiedName(),
+ rootRequestElement.getSimpleName(),
+ Joiner.on("\n")
+ .join(
+ FluentIterable.from(requestPath)
+ .transform(dependencyRequestFormatter)
+ .filter(not(equalTo("")))
+ .skip(1))),
+ kind,
+ rootRequestElement);
+ }
+
+ /**
+ * Returns {@code true} if any step of a dependency cycle after the first is a {@link Provider}
+ * or {@link Lazy} or a {@code Map<K, Provider<V>>}.
+ *
+ * <p>If an implicit {@link Provider} dependency on {@code Map<K, Provider<V>>} is immediately
+ * preceded by a dependency on {@code Map<K, V>}, which means that the map's {@link Provider}s'
+ * {@link Provider#get() get()} methods are called during provision and so the cycle is not
+ * really broken.
+ */
+ private boolean cycleHasProviderOrLazy(ImmutableList<DependencyRequest> cycle) {
+ DependencyRequest lastDependencyRequest = cycle.get(0);
+ for (DependencyRequest dependencyRequest : skip(cycle, 1)) {
+ switch (dependencyRequest.kind()) {
+ case PROVIDER:
+ if (!isImplicitProviderMapForValueMap(dependencyRequest, lastDependencyRequest)) {
+ return true;
+ }
+ break;
+
+ case LAZY:
+ return true;
+
+ case INSTANCE:
+ if (isMapWithProvidedValues(dependencyRequest.key().type())) {
+ return true;
+ } else {
+ break;
+ }
+
+ default:
+ break;
+ }
+ lastDependencyRequest = dependencyRequest;
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if {@code maybeValueMapRequest}'s key type is {@code Map<K, V>} and
+ * {@code maybeProviderMapRequest}'s key type is {@code Map<K, Provider<V>>}, and both keys have
+ * the same qualifier.
+ */
+ private boolean isImplicitProviderMapForValueMap(
+ DependencyRequest maybeProviderMapRequest, DependencyRequest maybeValueMapRequest) {
+ TypeMirror maybeProviderMapRequestType = maybeProviderMapRequest.key().type();
+ TypeMirror maybeValueMapRequestType = maybeValueMapRequest.key().type();
+ return maybeProviderMapRequest
+ .key()
+ .wrappedQualifier()
+ .equals(maybeValueMapRequest.key().wrappedQualifier())
+ && isMapWithProvidedValues(maybeProviderMapRequestType)
+ && isMapWithNonProvidedValues(maybeValueMapRequestType)
+ && types.isSameType(
+ getKeyTypeOfMap(asDeclared(maybeProviderMapRequestType)),
+ getKeyTypeOfMap(asDeclared(maybeValueMapRequestType)))
+ && types.isSameType(
+ getProvidedValueTypeOfMap(asDeclared(maybeProviderMapRequestType)),
+ getValueTypeOfMap(asDeclared(maybeValueMapRequestType)));
+ }
+ }
+
+ private boolean suppressCycleWarnings(Element requestElement) {
+ SuppressWarnings suppressions = requestElement.getAnnotation(SuppressWarnings.class);
+ return suppressions != null && Arrays.asList(suppressions.value()).contains("dependency-cycle");
+ }
+
+ private boolean suppressCycleWarnings(ImmutableList<DependencyRequest> pathElements) {
+ for (DependencyRequest dependencyRequest : pathElements) {
+ if (suppressCycleWarnings(dependencyRequest.requestElement())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ValidationReport<TypeElement> validate(BindingGraph subject) {
+ Validation validation = new Validation(subject);
+ validation.validateSubgraph();
+ return validation.buildReport();
+ }
+
+ /**
+ * Append and format 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);
+ Scope scope = Scope.scopeOf(scopedComponent);
+ if (scope.isPresent()) {
+ message.append(scope.getReadableSource()).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(Set<TypeElement> types) {
+ return FluentIterable.from(types).filter(new Predicate<TypeElement>() {
+ @Override public boolean apply(TypeElement input) {
+ return Scope.scopeOf(input).isPresent();
+ }
+ }).toSet();
+ }
+
+ /**
+ * Returns whether the given dependency path would require the most recent request to be resolved
+ * by only provision bindings.
+ */
+ private boolean doesPathRequireProvisionOnly(Deque<ResolvedRequest> path) {
+ if (path.size() == 1) {
+ // if this is an entry-point, then we check the request
+ switch (path.peek().request().kind()) {
+ case INSTANCE:
+ case PROVIDER:
+ case LAZY:
+ case MEMBERS_INJECTOR:
+ return true;
+ case PRODUCER:
+ case PRODUCED:
+ case FUTURE:
+ return false;
+ default:
+ throw new AssertionError();
+ }
+ }
+ // otherwise, the second-most-recent bindings determine whether the most recent one must be a
+ // provision
+ return !provisionsDependingOnLatestRequest(path).isEmpty();
+ }
+
+ /**
+ * Returns any provision bindings resolved for the second-most-recent request in the given path;
+ * that is, returns those provision bindings that depend on the latest request in the path.
+ */
+ private ImmutableSet<? extends Binding> provisionsDependingOnLatestRequest(
+ Deque<ResolvedRequest> path) {
+ Iterator<ResolvedRequest> iterator = path.iterator();
+ final DependencyRequest request = iterator.next().request();
+ ResolvedRequest previousResolvedRequest = iterator.next();
+ return FluentIterable.from(previousResolvedRequest.binding().bindings())
+ .filter(Binding.Type.PROVISION)
+ .filter(
+ new Predicate<Binding>() {
+ @Override
+ public boolean apply(Binding binding) {
+ return binding.implicitDependencies().contains(request);
+ }
+ })
+ .toSet();
+ }
+
+ private String formatBindingType(ContributionType type) {
+ switch (type) {
+ case MAP:
+ return "Map";
+ case SET:
+ return "Set";
+ case UNIQUE:
+ return "Unique";
+ default:
+ throw new IllegalStateException("Unknown binding type: " + type);
+ }
+ }
+
+ private String formatRootRequestKey(Deque<ResolvedRequest> path) {
+ return keyFormatter.format(path.peek().request().key());
+ }
+
+ private void appendBindings(
+ StringBuilder builder, Collection<ContributionBinding> bindings, int indentLevel) {
+ for (ContributionBinding binding : Iterables.limit(bindings, DUPLICATE_SIZE_LIMIT)) {
+ builder.append('\n');
+ for (int i = 0; i < indentLevel; i++) {
+ builder.append(INDENT);
+ }
+ builder.append(contributionBindingFormatter.format(binding));
+ }
+ int numberOfOtherBindings = bindings.size() - DUPLICATE_SIZE_LIMIT;
+ if (numberOfOtherBindings > 0) {
+ builder.append('\n');
+ for (int i = 0; i < indentLevel; i++) {
+ builder.append(INDENT);
+ }
+ builder.append("and ").append(numberOfOtherBindings).append(" other");
+ }
+ if (numberOfOtherBindings > 1) {
+ builder.append('s');
+ }
+ }
+
+ @AutoValue
+ abstract static class ResolvedRequest {
+ abstract DependencyRequest request();
+ abstract ResolvedBindings binding();
+
+ static ResolvedRequest create(DependencyRequest request, BindingGraph graph) {
+ BindingKey bindingKey = request.bindingKey();
+ ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey);
+ return new AutoValue_BindingGraphValidator_ResolvedRequest(
+ request,
+ resolvedBindings == null
+ ? ResolvedBindings.noBindings(bindingKey, graph.componentDescriptor())
+ : resolvedBindings);
+ }
+ }
+
+ private static final Function<ResolvedRequest, DependencyRequest> REQUEST_FROM_RESOLVED_REQUEST =
+ new Function<ResolvedRequest, DependencyRequest>() {
+ @Override public DependencyRequest apply(ResolvedRequest resolvedRequest) {
+ return resolvedRequest.request();
+ }
+ };
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingKey.java b/compiler/src/main/java/dagger/internal/codegen/BindingKey.java
new file mode 100644
index 0000000..cd29d8d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BindingKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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;
+
+/**
+ * A value object that pairs a {@link Key} with the style of its binding (i.e., whether it's a
+ * members injector or normal contribution).
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class BindingKey {
+ /** The style of binding that makes a {@link Key} available. */
+ enum Kind {
+ CONTRIBUTION, MEMBERS_INJECTION;
+ }
+
+ static BindingKey create(Kind kind, Key key) {
+ return new AutoValue_BindingKey(kind, key);
+ }
+
+ abstract Kind kind();
+ abstract Key key();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java b/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java
new file mode 100644
index 0000000..ba96ebf
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/BuilderValidator.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.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.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Validates {@link dagger.Component.Builder} annotations.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ */
+class BuilderValidator {
+ private final Elements elements;
+ private final Types types;
+ private final ComponentDescriptor.Kind componentType;
+
+ BuilderValidator(Elements elements, Types types, ComponentDescriptor.Kind componentType) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = componentType;
+ }
+
+ public ValidationReport<TypeElement> validate(TypeElement subject) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ Element componentElement = subject.getEnclosingElement();
+ ErrorMessages.ComponentBuilderMessages msgs = ErrorMessages.builderMsgsFor(componentType);
+ Class<? extends Annotation> componentAnnotation = componentType.annotationType();
+ Class<? extends Annotation> builderAnnotation = componentType.builderAnnotationType();
+ checkArgument(subject.getAnnotation(builderAnnotation) != null);
+
+ if (!isAnnotationPresent(componentElement, componentAnnotation)) {
+ builder.addError(msgs.mustBeInComponent(), subject);
+ }
+
+ switch (subject.getKind()) {
+ case CLASS:
+ List<? extends Element> allElements = subject.getEnclosedElements();
+ List<ExecutableElement> cxtors = ElementFilter.constructorsIn(allElements);
+ if (cxtors.size() != 1 || getOnlyElement(cxtors).getParameters().size() != 0) {
+ builder.addError(msgs.cxtorOnlyOneAndNoArgs(), subject);
+ }
+ break;
+ case INTERFACE:
+ break;
+ default:
+ // If not the correct type, exit early since the rest of the messages will be bogus.
+ builder.addError(msgs.mustBeClassOrInterface(), subject);
+ return builder.build();
+ }
+
+ if (!subject.getTypeParameters().isEmpty()) {
+ builder.addError(msgs.generics(), subject);
+ }
+
+ Set<Modifier> modifiers = subject.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(msgs.isPrivate(), subject);
+ }
+ if (!modifiers.contains(STATIC)) {
+ builder.addError(msgs.mustBeStatic(), subject);
+ }
+ // Note: Must be abstract, so no need to check for final.
+ if (!modifiers.contains(ABSTRACT)) {
+ builder.addError(msgs.mustBeAbstract(), subject);
+ }
+
+ ExecutableElement buildMethod = null;
+ Multimap<Equivalence.Wrapper<TypeMirror>, ExecutableElement> methodsPerParam =
+ LinkedHashMultimap.create();
+ for (ExecutableElement method : Util.getUnimplementedMethods(elements, subject)) {
+ ExecutableType resolvedMethodType =
+ MoreTypes.asExecutable(types.asMemberOf(MoreTypes.asDeclared(subject.asType()), method));
+ TypeMirror returnType = resolvedMethodType.getReturnType();
+ if (method.getParameters().size() == 0) {
+ // If this is potentially a build() method, validate it returns the correct type.
+ if (types.isSameType(returnType, componentElement.asType())) {
+ if (buildMethod != null) {
+ // If we found more than one build-like method, fail.
+ error(builder, method, msgs.twoBuildMethods(), msgs.inheritedTwoBuildMethods(),
+ buildMethod);
+ }
+ } else {
+ error(builder, method, msgs.buildMustReturnComponentType(),
+ msgs.inheritedBuildMustReturnComponentType());
+ }
+ // We set the buildMethod regardless of the return type to reduce error spam.
+ buildMethod = method;
+ } else if (method.getParameters().size() > 1) {
+ // If this is a setter, make sure it has one arg.
+ error(builder, method, msgs.methodsMustTakeOneArg(), msgs.inheritedMethodsMustTakeOneArg());
+ } else if (returnType.getKind() != TypeKind.VOID
+ && !types.isSubtype(subject.asType(), returnType)) {
+ // If this correctly had one arg, make sure the return types are valid.
+ error(builder, method, msgs.methodsMustReturnVoidOrBuilder(),
+ msgs.inheritedMethodsMustReturnVoidOrBuilder());
+ } else {
+ // If the return types are valid, record the method.
+ methodsPerParam.put(
+ MoreTypes.equivalence().<TypeMirror>wrap(
+ Iterables.getOnlyElement(resolvedMethodType.getParameterTypes())),
+ method);
+ }
+
+ if (!method.getTypeParameters().isEmpty()) {
+ error(builder, method, msgs.methodsMayNotHaveTypeParameters(),
+ msgs.inheritedMethodsMayNotHaveTypeParameters());
+ }
+ }
+
+ if (buildMethod == null) {
+ builder.addError(msgs.missingBuildMethod(), subject);
+ }
+
+ // Go back through each recorded method per param type. If we had more than one method
+ // for a given param, fail.
+ for (Map.Entry<Equivalence.Wrapper<TypeMirror>, Collection<ExecutableElement>> entry :
+ methodsPerParam.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ TypeMirror type = entry.getKey().get();
+ builder.addError(String.format(msgs.manyMethodsForType(), type, entry.getValue()), subject);
+ }
+ }
+
+ // Note: there's more validation in BindingGraphValidator,
+ // specifically to make sure the setter methods mirror the deps.
+
+ return builder.build();
+ }
+
+ /**
+ * 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 argumnent. (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(
+ ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method,
+ String enclosedError,
+ String inheritedError,
+ Object... extraArgs) {
+ if (method.getEnclosingElement().equals(builder.getSubject())) {
+ builder.addError(String.format(enclosedError, extraArgs), method);
+ } else {
+ Object[] newArgs = new Object[extraArgs.length + 1];
+ newArgs[0] = method;
+ System.arraycopy(extraArgs, 0, newArgs, 1, extraArgs.length);
+ builder.addError(String.format(inheritedError, newArgs), builder.getSubject());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java
new file mode 100644
index 0000000..650fb9d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+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.util.concurrent.ListenableFuture;
+import dagger.Component;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+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.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static dagger.internal.codegen.ConfigurationAnnotations.isComponent;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * The logical representation of a {@link Component} or {@link ProductionComponent} definition.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ComponentDescriptor {
+ ComponentDescriptor() {}
+
+ enum Kind {
+ COMPONENT(Component.class, Component.Builder.class, true),
+ SUBCOMPONENT(Subcomponent.class, Subcomponent.Builder.class, false),
+ PRODUCTION_COMPONENT(ProductionComponent.class, ProductionComponent.Builder.class, true);
+
+ private final Class<? extends Annotation> annotationType;
+ private final Class<? extends Annotation> builderType;
+ private final boolean isTopLevel;
+
+ /**
+ * Returns the kind of an annotated element if it is annotated with one of the
+ * {@linkplain #annotationType() annotation types}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one of the
+ * annotation types
+ */
+ static Optional<Kind> forAnnotatedElement(TypeElement element) {
+ Set<Kind> kinds = EnumSet.noneOf(Kind.class);
+ for (Kind kind : values()) {
+ if (MoreElements.isAnnotationPresent(element, kind.annotationType())) {
+ kinds.add(kind);
+ }
+ }
+ checkArgument(
+ kinds.size() <= 1, "%s cannot be annotated with more than one of %s", element, kinds);
+ return Optional.fromNullable(getOnlyElement(kinds, null));
+ }
+
+ Kind(
+ Class<? extends Annotation> annotationType,
+ Class<? extends Annotation> builderType,
+ boolean isTopLevel) {
+ this.annotationType = annotationType;
+ this.builderType = builderType;
+ this.isTopLevel = isTopLevel;
+ }
+
+ Class<? extends Annotation> annotationType() {
+ return annotationType;
+ }
+
+ Class<? extends Annotation> builderAnnotationType() {
+ return builderType;
+ }
+
+ boolean isTopLevel() {
+ return isTopLevel;
+ }
+ }
+
+ abstract Kind kind();
+
+ abstract AnnotationMirror componentAnnotation();
+
+ /**
+ * The type (interface or abstract class) that defines the component. This is the element to which
+ * the {@link Component} annotation was applied.
+ */
+ abstract TypeElement componentDefinitionType();
+
+ /**
+ * The set of component dependencies listed in {@link Component#dependencies}.
+ */
+ abstract ImmutableSet<TypeElement> dependencies();
+
+ /**
+ * The set of {@link ModuleDescriptor modules} declared directly in {@link Component#modules}.
+ * Use {@link #transitiveModules} to get the full set of modules available upon traversing
+ * {@link Module#includes}.
+ */
+ abstract ImmutableSet<ModuleDescriptor> modules();
+
+ /**
+ * Returns the set of {@link ModuleDescriptor modules} declared in {@link Component#modules} and
+ * those reachable by traversing {@link Module#includes}.
+ *
+ * <p>Note that for subcomponents this <em>will not</em> include descriptors for any modules that
+ * are declared in parent components.
+ */
+ ImmutableSet<ModuleDescriptor> transitiveModules() {
+ Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>();
+ for (ModuleDescriptor module : modules()) {
+ addTransitiveModules(transitiveModules, module);
+ }
+ return ImmutableSet.copyOf(transitiveModules);
+ }
+
+ ImmutableSet<TypeElement> transitiveModuleTypes() {
+ return FluentIterable.from(transitiveModules())
+ .transform(ModuleDescriptor.getModuleElement())
+ .toSet();
+ }
+
+ private static Set<ModuleDescriptor> addTransitiveModules(
+ Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) {
+ if (transitiveModules.add(module)) {
+ for (ModuleDescriptor includedModule : module.includedModules()) {
+ addTransitiveModules(transitiveModules, includedModule);
+ }
+ }
+ return transitiveModules;
+ }
+
+ /**
+ * An index of the type to which this component holds a reference (the type listed in
+ * {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the
+ * enclosing type) for each method from a component dependency that can be used for binding.
+ */
+ abstract ImmutableMap<ExecutableElement, TypeElement> dependencyMethodIndex();
+
+ /**
+ * The element representing {@link Executor}, if it should be a dependency of this component.
+ */
+ abstract Optional<TypeElement> executorDependency();
+
+ /**
+ * The scope of the component.
+ */
+ abstract Scope scope();
+
+ abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponents();
+
+ abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
+
+ // TODO(gak): Consider making this non-optional and revising the
+ // interaction between the spec & generation
+ abstract Optional<BuilderSpec> builderSpec();
+
+ @AutoValue
+ static abstract class ComponentMethodDescriptor {
+ abstract ComponentMethodKind kind();
+ abstract Optional<DependencyRequest> dependencyRequest();
+ abstract ExecutableElement methodElement();
+
+ /**
+ * A predicate that passes for {@link ComponentMethodDescriptor}s of a given kind.
+ */
+ static Predicate<ComponentMethodDescriptor> isOfKind(final ComponentMethodKind kind) {
+ return new Predicate<ComponentMethodDescriptor>() {
+ @Override
+ public boolean apply(ComponentMethodDescriptor descriptor) {
+ return kind.equals(descriptor.kind());
+ }
+ };
+ }
+ }
+
+ enum ComponentMethodKind {
+ PROVISON,
+ PRODUCTION,
+ MEMBERS_INJECTION,
+ SUBCOMPONENT,
+ SUBCOMPONENT_BUILDER,
+ }
+
+ @AutoValue
+ static abstract class BuilderSpec {
+ abstract TypeElement builderDefinitionType();
+ abstract Map<TypeElement, ExecutableElement> methodMap();
+ abstract ExecutableElement buildMethod();
+ abstract TypeMirror componentType();
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+ private final ModuleDescriptor.Factory moduleDescriptorFactory;
+
+ Factory(
+ Elements elements,
+ Types types,
+ DependencyRequest.Factory dependencyRequestFactory,
+ ModuleDescriptor.Factory moduleDescriptorFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ this.moduleDescriptorFactory = moduleDescriptorFactory;
+ }
+
+ /**
+ * Returns a component descriptor for a type annotated with either {@link Component @Component}
+ * or {@link ProductionComponent @ProductionComponent}.
+ */
+ ComponentDescriptor forComponent(TypeElement componentDefinitionType) {
+ Optional<Kind> kind = Kind.forAnnotatedElement(componentDefinitionType);
+ checkArgument(
+ kind.isPresent() && kind.get().isTopLevel(),
+ "%s must be annotated with @Component or @ProductionComponent",
+ componentDefinitionType);
+ return create(componentDefinitionType, kind.get());
+ }
+
+ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) {
+ DeclaredType declaredComponentType = MoreTypes.asDeclared(componentDefinitionType.asType());
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(componentDefinitionType, kind.annotationType())
+ .or(getAnnotationMirror(componentDefinitionType, Subcomponent.class))
+ .get();
+ ImmutableSet<TypeElement> componentDependencyTypes =
+ isComponent(componentDefinitionType)
+ ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror))
+ : ImmutableSet.<TypeElement>of();
+
+ ImmutableMap.Builder<ExecutableElement, TypeElement> dependencyMethodIndex =
+ ImmutableMap.builder();
+
+ for (TypeElement componentDependency : componentDependencyTypes) {
+ List<ExecutableElement> dependencyMethods =
+ ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
+ for (ExecutableElement dependencyMethod : dependencyMethods) {
+ if (isComponentContributionMethod(elements, dependencyMethod)) {
+ dependencyMethodIndex.put(dependencyMethod, componentDependency);
+ }
+ }
+ }
+
+ Optional<TypeElement> executorDependency =
+ kind.equals(Kind.PRODUCTION_COMPONENT)
+ ? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName()))
+ : Optional.<TypeElement>absent();
+
+ ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
+ for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
+ modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
+ }
+ if (kind.equals(Kind.PRODUCTION_COMPONENT)) {
+ modules.add(descriptorForMonitoringModule(componentDefinitionType));
+ }
+
+ ImmutableSet<ExecutableElement> unimplementedMethods =
+ Util.getUnimplementedMethods(elements, componentDefinitionType);
+
+ ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
+ ImmutableSet.builder();
+
+ ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> subcomponentDescriptors =
+ ImmutableMap.builder();
+ for (ExecutableElement componentMethod : unimplementedMethods) {
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredComponentType, componentMethod));
+ ComponentMethodDescriptor componentMethodDescriptor =
+ getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod);
+ componentMethodsBuilder.add(componentMethodDescriptor);
+ switch (componentMethodDescriptor.kind()) {
+ case SUBCOMPONENT:
+ subcomponentDescriptors.put(
+ componentMethodDescriptor,
+ create(
+ MoreElements.asType(MoreTypes.asElement(resolvedMethod.getReturnType())),
+ Kind.SUBCOMPONENT));
+ break;
+ case SUBCOMPONENT_BUILDER:
+ subcomponentDescriptors.put(
+ componentMethodDescriptor,
+ create(
+ MoreElements.asType(
+ MoreTypes.asElement(resolvedMethod.getReturnType()).getEnclosingElement()),
+ Kind.SUBCOMPONENT));
+ break;
+ default: // nothing special to do for other methods.
+ }
+
+ }
+
+ ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null
+ ? ImmutableList.<DeclaredType>of()
+ : enclosedBuilders(componentDefinitionType, kind.builderAnnotationType());
+ Optional<DeclaredType> builderType =
+ Optional.fromNullable(getOnlyElement(enclosedBuilders, null));
+
+ Scope scope = Scope.scopeOf(componentDefinitionType);
+ return new AutoValue_ComponentDescriptor(
+ kind,
+ componentMirror,
+ componentDefinitionType,
+ componentDependencyTypes,
+ modules.build(),
+ dependencyMethodIndex.build(),
+ executorDependency,
+ scope,
+ subcomponentDescriptors.build(),
+ componentMethodsBuilder.build(),
+ createBuilderSpec(builderType));
+ }
+
+ private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement,
+ Kind componentKind,
+ ExecutableElement componentMethod) {
+ ExecutableType resolvedComponentMethod = MoreTypes.asExecutable(types.asMemberOf(
+ MoreTypes.asDeclared(componentElement.asType()), componentMethod));
+ TypeMirror returnType = resolvedComponentMethod.getReturnType();
+ if (returnType.getKind().equals(DECLARED)) {
+ if (MoreTypes.isTypeOf(Provider.class, returnType)
+ || MoreTypes.isTypeOf(Lazy.class, returnType)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PROVISON,
+ Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.MEMBERS_INJECTION,
+ Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
+ componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ } else if (isAnnotationPresent(MoreTypes.asElement(returnType), Subcomponent.class)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.SUBCOMPONENT,
+ Optional.<DependencyRequest>absent(),
+ componentMethod);
+ } else if (isAnnotationPresent(MoreTypes.asElement(returnType),
+ Subcomponent.Builder.class)) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.SUBCOMPONENT_BUILDER,
+ Optional.<DependencyRequest>absent(),
+ componentMethod);
+ }
+ }
+
+ // a typical provision method
+ if (componentMethod.getParameters().isEmpty()
+ && !componentMethod.getReturnType().getKind().equals(VOID)) {
+ switch (componentKind) {
+ case COMPONENT:
+ case SUBCOMPONENT:
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PROVISON,
+ Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ case PRODUCTION_COMPONENT:
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.PRODUCTION,
+ Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ List<? extends TypeMirror> parameterTypes = resolvedComponentMethod.getParameterTypes();
+ if (parameterTypes.size() == 1
+ && (returnType.getKind().equals(VOID)
+ || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
+ ComponentMethodKind.MEMBERS_INJECTION,
+ Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
+ componentMethod,
+ resolvedComponentMethod)),
+ componentMethod);
+ }
+
+ throw new IllegalArgumentException("not a valid component method: " + componentMethod);
+ }
+
+ private Optional<BuilderSpec> createBuilderSpec(Optional<DeclaredType> builderType) {
+ if (!builderType.isPresent()) {
+ return Optional.absent();
+ }
+ TypeElement element = MoreTypes.asTypeElement(builderType.get());
+ ImmutableSet<ExecutableElement> methods = Util.getUnimplementedMethods(elements, element);
+ ImmutableMap.Builder<TypeElement, ExecutableElement> map = ImmutableMap.builder();
+ ExecutableElement buildMethod = null;
+ for (ExecutableElement method : methods) {
+ if (method.getParameters().isEmpty()) {
+ buildMethod = method;
+ } else {
+ ExecutableType resolved =
+ MoreTypes.asExecutable(types.asMemberOf(builderType.get(), method));
+ map.put(MoreTypes.asTypeElement(getOnlyElement(resolved.getParameterTypes())), method);
+ }
+ }
+ verify(buildMethod != null); // validation should have ensured this.
+ return Optional.<BuilderSpec>of(new AutoValue_ComponentDescriptor_BuilderSpec(element,
+ map.build(), buildMethod, element.getEnclosingElement().asType()));
+ }
+
+ /**
+ * 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) {
+ String generatedMonitorModuleName =
+ SourceFiles.generatedMonitoringModuleName(componentDefinitionType).canonicalName();
+ TypeElement monitoringModule = elements.getTypeElement(generatedMonitorModuleName);
+ if (monitoringModule == null) {
+ throw new TypeNotPresentException(generatedMonitorModuleName, null);
+ }
+ return moduleDescriptorFactory.create(monitoringModule);
+ }
+ }
+
+ static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) {
+ return method.getParameters().isEmpty()
+ && !method.getReturnType().getKind().equals(VOID)
+ && !elements.getTypeElement(Object.class.getCanonicalName())
+ .equals(method.getEnclosingElement());
+ }
+
+ static boolean isComponentProductionMethod(Elements elements, ExecutableElement method) {
+ return isComponentContributionMethod(elements, method)
+ && MoreTypes.isTypeOf(ListenableFuture.class, method.getReturnType());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java
new file mode 100644
index 0000000..72e761c
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.Component;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+/**
+ * Generates the implementation of the abstract types annotated with {@link Component}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
+ private final Types types;
+ private final Elements elements;
+ private final Key.Factory keyFactory;
+ private final Diagnostic.Kind nullableValidationType;
+
+ ComponentGenerator(
+ Filer filer,
+ Elements elements,
+ Types types,
+ Key.Factory keyFactory,
+ Diagnostic.Kind nullableValidationType) {
+ super(filer);
+ this.types = types;
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ this.nullableValidationType = nullableValidationType;
+ }
+
+ @Override
+ ClassName nameGeneratedType(BindingGraph input) {
+ ClassName componentDefinitionClassName =
+ ClassName.fromTypeElement(input.componentDescriptor().componentDefinitionType());
+ String componentName = "Dagger" + componentDefinitionClassName.classFileName('_');
+ return componentDefinitionClassName.topLevelClassName().peerNamed(componentName);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(BindingGraph input) {
+ return ImmutableSet.of(input.componentDescriptor().componentDefinitionType());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(BindingGraph input) {
+ return Optional.of(input.componentDescriptor().componentDefinitionType());
+ }
+
+ @AutoValue static abstract class MemberSelect {
+ static MemberSelect instanceSelect(ClassName owningClass, Snippet snippet) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.<TypeName> absent(), owningClass, false, snippet);
+ }
+
+ static MemberSelect staticSelect(ClassName owningClass, Snippet snippet) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.<TypeName> absent(), owningClass, true, snippet);
+ }
+
+ static MemberSelect staticMethodInvocationWithCast(
+ ClassName owningClass, Snippet snippet, TypeName castType) {
+ return new AutoValue_ComponentGenerator_MemberSelect(
+ Optional.of(castType), owningClass, true, snippet);
+ }
+
+ /**
+ * This exists only to facilitate edge cases in which we need to select a member, but that
+ * member uses a type parameter that can't be inferred.
+ */
+ abstract Optional<TypeName> selectedCast();
+ abstract ClassName owningClass();
+ abstract boolean staticMember();
+ abstract Snippet snippet();
+
+ private Snippet qualifiedSelectSnippet() {
+ return Snippet.format(
+ "%s" + (staticMember() ? "" : ".this") + ".%s",
+ owningClass(), snippet());
+ }
+
+ Snippet getSnippetWithRawTypeCastFor(ClassName usingClass) {
+ Snippet snippet = getSnippetFor(usingClass);
+ return selectedCast().isPresent()
+ ? Snippet.format("(%s) %s", selectedCast().get(), snippet)
+ : snippet;
+ }
+
+ Snippet getSnippetFor(ClassName usingClass) {
+ return owningClass().equals(usingClass) ? snippet() : qualifiedSelectSnippet();
+ }
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName componentName, BindingGraph input) {
+ return new ComponentWriter(
+ types, elements, keyFactory, nullableValidationType, componentName, input)
+ .write();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java
new file mode 100644
index 0000000..8fb4191
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentHierarchyValidator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import java.util.Map;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+
+import static com.google.common.base.Functions.constant;
+
+/**
+ * Validates the relationships between parent components and subcomponents.
+ */
+final class ComponentHierarchyValidator {
+ ValidationReport<TypeElement> validate(ComponentDescriptor componentDescriptor) {
+ return validateSubcomponentMethods(
+ componentDescriptor,
+ Maps.toMap(
+ componentDescriptor.transitiveModuleTypes(),
+ constant(componentDescriptor.componentDefinitionType())));
+ }
+
+ private ValidationReport<TypeElement> validateSubcomponentMethods(
+ ComponentDescriptor componentDescriptor,
+ Map<TypeElement, TypeElement> existingModuleToOwners) {
+ ValidationReport.Builder<TypeElement> reportBuilder =
+ ValidationReport.about(componentDescriptor.componentDefinitionType());
+ for (Map.Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry :
+ componentDescriptor.subcomponents().entrySet()) {
+ ComponentMethodDescriptor subcomponentMethodDescriptor = subcomponentEntry.getKey();
+ ComponentDescriptor subcomponentDescriptor = subcomponentEntry.getValue();
+ // validate the way that we create subcomponents
+ switch (subcomponentMethodDescriptor.kind()) {
+ case SUBCOMPONENT:
+ for (VariableElement factoryMethodParameter :
+ subcomponentMethodDescriptor.methodElement().getParameters()) {
+ TypeElement origininatingComponent =
+ existingModuleToOwners.get(
+ MoreTypes.asTypeElement(factoryMethodParameter.asType()));
+ if (origininatingComponent != null) {
+ /* Factory method tries to pass a module that is already present in the parent.
+ * This is an error. */
+ reportBuilder.addError(
+ String.format(
+ "This module is present in %s. Subcomponents cannot use an instance of a "
+ + "module that differs from its parent.",
+ origininatingComponent.getQualifiedName()),
+ factoryMethodParameter);
+ }
+ }
+ break;
+ case SUBCOMPONENT_BUILDER:
+ BuilderSpec subcomponentBuilderSpec = subcomponentDescriptor.builderSpec().get();
+ for (Map.Entry<TypeElement, ExecutableElement> builderMethodEntry :
+ subcomponentBuilderSpec.methodMap().entrySet()) {
+ TypeElement origininatingComponent =
+ existingModuleToOwners.get(builderMethodEntry.getKey());
+ if (origininatingComponent != null) {
+ /* A subcomponent builder allows you to pass a module that is already present in the
+ * parent. This can't be an error because it might be valid in _other_ components, so
+ * we warn here. */
+ ExecutableElement builderMethodElement = builderMethodEntry.getValue();
+ /* TODO(gak): consider putting this on the builder method directly if it's in the
+ * component being compiled */
+ reportBuilder.addWarning(
+ String.format(
+ "This module is present in %s. Subcomponents cannot use an instance of a "
+ + "module that differs from its parent. The implementation of %s "
+ + "in this component will throw %s.",
+ origininatingComponent.getQualifiedName(),
+ builderMethodElement.getSimpleName(),
+ UnsupportedOperationException.class.getSimpleName()),
+ builderMethodElement);
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ reportBuilder.addSubreport(
+ validateSubcomponentMethods(
+ subcomponentDescriptor,
+ new ImmutableMap.Builder<TypeElement, TypeElement>()
+ .putAll(existingModuleToOwners)
+ .putAll(
+ Maps.toMap(
+ Sets.difference(
+ subcomponentDescriptor.transitiveModuleTypes(),
+ existingModuleToOwners.keySet()),
+ constant(subcomponentDescriptor.componentDefinitionType())))
+ .build()));
+ }
+ return reportBuilder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java
new file mode 100644
index 0000000..39b21ca
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.internal.codegen.ComponentDescriptor.Factory;
+import dagger.internal.codegen.ComponentValidator.ComponentValidationReport;
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@link ProcessingStep} that is responsible for dealing with the {@link Component} annotation
+ * as part of the {@link ComponentProcessor}.
+ *
+ * @author Gregory Kick
+ */
+final class ComponentProcessingStep extends AbstractComponentProcessingStep {
+ private final Messager messager;
+ private final ComponentValidator componentValidator;
+ private final ComponentValidator subcomponentValidator;
+ private final BuilderValidator componentBuilderValidator;
+ private final BuilderValidator subcomponentBuilderValidator;
+
+ ComponentProcessingStep(
+ Messager messager,
+ ComponentValidator componentValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator componentBuilderValidator,
+ BuilderValidator subcomponentBuilderValidator,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ super(
+ Component.class,
+ messager,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator);
+ this.messager = messager;
+ this.componentValidator = componentValidator;
+ this.subcomponentValidator = subcomponentValidator;
+ this.componentBuilderValidator = componentBuilderValidator;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(Component.class, Component.Builder.class,
+ Subcomponent.class, Subcomponent.Builder.class);
+ }
+
+ @Override
+ protected ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ final Map<Element, ValidationReport<TypeElement>> builderReportsByComponent =
+ processComponentBuilders(elementsByAnnotation.get(Component.Builder.class));
+ final Set<Element> subcomponentBuilderElements =
+ elementsByAnnotation.get(Subcomponent.Builder.class);
+ final Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent =
+ processSubcomponentBuilders(subcomponentBuilderElements);
+ final Set<Element> subcomponentElements = elementsByAnnotation.get(Subcomponent.class);
+ final Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent =
+ processSubcomponents(subcomponentElements, subcomponentBuilderElements);
+ return new ComponentElementValidator() {
+ @Override
+ boolean validateComponent(TypeElement componentTypeElement, Messager messager) {
+ ComponentValidationReport validationReport =
+ componentValidator.validate(
+ componentTypeElement, subcomponentElements, subcomponentBuilderElements);
+ validationReport.report().printMessagesTo(messager);
+ return isClean(
+ validationReport,
+ builderReportsByComponent,
+ reportsBySubcomponent,
+ builderReportsBySubcomponent);
+ }
+ };
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processComponentBuilders(
+ Set<? extends Element> componentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> builderReportsByComponent = Maps.newHashMap();
+ for (Element element : componentBuilderElements) {
+ ValidationReport<TypeElement> report =
+ componentBuilderValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ builderReportsByComponent.put(element.getEnclosingElement(), report);
+ }
+ return builderReportsByComponent;
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processSubcomponentBuilders(
+ Set<? extends Element> subcomponentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent = Maps.newHashMap();
+ for (Element element : subcomponentBuilderElements) {
+ ValidationReport<TypeElement> report =
+ subcomponentBuilderValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ builderReportsBySubcomponent.put(element, report);
+ }
+ return builderReportsBySubcomponent;
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processSubcomponents(
+ Set<? extends Element> subcomponentElements,
+ Set<? extends Element> subcomponentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent = Maps.newHashMap();
+ for (Element element : subcomponentElements) {
+ ComponentValidationReport report = subcomponentValidator.validate(
+ MoreElements.asType(element), subcomponentElements, subcomponentBuilderElements);
+ report.report().printMessagesTo(messager);
+ reportsBySubcomponent.put(element, report.report());
+ }
+ return reportsBySubcomponent;
+ }
+
+ /**
+ * Returns true if the component's report is clean, its builder report is clean, and all
+ * referenced subcomponent reports & subcomponent builder reports are clean.
+ */
+ private boolean isClean(ComponentValidationReport report,
+ Map<Element, ValidationReport<TypeElement>> builderReportsByComponent,
+ Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent,
+ Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent) {
+ Element component = report.report().subject();
+ ValidationReport<?> componentReport = report.report();
+ if (!componentReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> builderReport = builderReportsByComponent.get(component);
+ if (builderReport != null && !builderReport.isClean()) {
+ return false;
+ }
+ for (Element element : report.referencedSubcomponents()) {
+ ValidationReport<?> subcomponentBuilderReport = builderReportsBySubcomponent.get(element);
+ if (subcomponentBuilderReport != null && !subcomponentBuilderReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> subcomponentReport = reportsBySubcomponent.get(element);
+ if (subcomponentReport != null && !subcomponentReport.isClean()) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java
new file mode 100644
index 0000000..c35058b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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;
+import com.google.auto.service.AutoService;
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+/**
+ * The annotation processor responsible for generating the classes that drive the Dagger 2.0
+ * implementation.
+ *
+ * TODO(gak): give this some better documentation
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoService(Processor.class)
+public final class ComponentProcessor extends BasicAnnotationProcessor {
+ private InjectBindingRegistry injectBindingRegistry;
+ private FactoryGenerator factoryGenerator;
+ private MembersInjectorGenerator membersInjectorGenerator;
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
+ public Set<String> getSupportedOptions() {
+ return ImmutableSet.of(
+ DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
+ NULLABLE_VALIDATION_KEY,
+ PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
+ STATIC_MEMBER_VALIDATION_TYPE_KEY
+ );
+ }
+
+ @Override
+ protected Iterable<ProcessingStep> initSteps() {
+ Messager messager = processingEnv.getMessager();
+ Types types = processingEnv.getTypeUtils();
+ Elements elements = processingEnv.getElementUtils();
+ Filer filer = processingEnv.getFiler();
+
+ Diagnostic.Kind nullableDiagnosticType =
+ nullableValidationType(processingEnv).diagnosticKind().get();
+
+ MethodSignatureFormatter methodSignatureFormatter = new MethodSignatureFormatter(types);
+ ContributionBindingFormatter contributionBindingFormatter =
+ new ContributionBindingFormatter(methodSignatureFormatter);
+ DependencyRequestFormatter dependencyRequestFormatter = new DependencyRequestFormatter(types);
+ KeyFormatter keyFormatter = new KeyFormatter();
+
+ InjectConstructorValidator injectConstructorValidator = new InjectConstructorValidator();
+ InjectFieldValidator injectFieldValidator = new InjectFieldValidator(
+ privateMemberValidationType(processingEnv).diagnosticKind().get(),
+ staticMemberValidationType(processingEnv).diagnosticKind().get());
+ InjectMethodValidator injectMethodValidator = new InjectMethodValidator(
+ privateMemberValidationType(processingEnv).diagnosticKind().get(),
+ staticMemberValidationType(processingEnv).diagnosticKind().get());
+ ModuleValidator moduleValidator =
+ new ModuleValidator(
+ types,
+ elements,
+ methodSignatureFormatter,
+ Module.class,
+ ImmutableList.<Class<? extends Annotation>>of(Module.class),
+ Provides.class);
+ ProvidesMethodValidator providesMethodValidator = new ProvidesMethodValidator(elements);
+ BuilderValidator componentBuilderValidator =
+ new BuilderValidator(elements, types, ComponentDescriptor.Kind.COMPONENT);
+ BuilderValidator subcomponentBuilderValidator =
+ new BuilderValidator(elements, types, ComponentDescriptor.Kind.SUBCOMPONENT);
+ ComponentValidator subcomponentValidator = ComponentValidator.createForSubcomponent(elements,
+ types, moduleValidator, subcomponentBuilderValidator);
+ ComponentValidator componentValidator = ComponentValidator.createForComponent(elements, types,
+ moduleValidator, subcomponentValidator, subcomponentBuilderValidator);
+ MapKeyValidator mapKeyValidator = new MapKeyValidator();
+ ModuleValidator producerModuleValidator =
+ new ModuleValidator(
+ types,
+ elements,
+ methodSignatureFormatter,
+ ProducerModule.class,
+ ImmutableList.of(Module.class, ProducerModule.class),
+ Produces.class);
+ ProducesMethodValidator producesMethodValidator = new ProducesMethodValidator(elements);
+ ProductionComponentValidator productionComponentValidator = new ProductionComponentValidator();
+ BuilderValidator productionComponentBuilderValidator =
+ new BuilderValidator(elements, types, ComponentDescriptor.Kind.PRODUCTION_COMPONENT);
+
+ Key.Factory keyFactory = new Key.Factory(types, elements);
+
+ this.factoryGenerator =
+ new FactoryGenerator(filer, DependencyRequestMapper.FOR_PROVIDER, nullableDiagnosticType);
+ this.membersInjectorGenerator =
+ new MembersInjectorGenerator(filer, DependencyRequestMapper.FOR_PROVIDER);
+ ComponentGenerator componentGenerator =
+ new ComponentGenerator(filer, elements, types, keyFactory, nullableDiagnosticType);
+ ProducerFactoryGenerator producerFactoryGenerator =
+ new ProducerFactoryGenerator(filer, DependencyRequestMapper.FOR_PRODUCER);
+ MonitoringModuleGenerator monitoringModuleGenerator = new MonitoringModuleGenerator(filer);
+
+ DependencyRequest.Factory dependencyRequestFactory =
+ new DependencyRequest.Factory(elements, keyFactory);
+ ProvisionBinding.Factory provisionBindingFactory =
+ new ProvisionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
+ ProductionBinding.Factory productionBindingFactory =
+ new ProductionBinding.Factory(types, keyFactory, dependencyRequestFactory);
+
+ MembersInjectionBinding.Factory membersInjectionBindingFactory =
+ new MembersInjectionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
+
+ this.injectBindingRegistry = new InjectBindingRegistry(
+ elements, types, messager, provisionBindingFactory, membersInjectionBindingFactory);
+
+ ModuleDescriptor.Factory moduleDescriptorFactory = new ModuleDescriptor.Factory(
+ elements, provisionBindingFactory, productionBindingFactory);
+
+ ComponentDescriptor.Factory componentDescriptorFactory = new ComponentDescriptor.Factory(
+ elements, types, dependencyRequestFactory, moduleDescriptorFactory);
+
+ BindingGraph.Factory bindingGraphFactory =
+ new BindingGraph.Factory(
+ elements,
+ injectBindingRegistry,
+ keyFactory,
+ provisionBindingFactory,
+ productionBindingFactory);
+
+ MapKeyGenerator mapKeyGenerator = new MapKeyGenerator(filer);
+ ComponentHierarchyValidator componentHierarchyValidator = new ComponentHierarchyValidator();
+ BindingGraphValidator bindingGraphValidator =
+ new BindingGraphValidator(
+ types,
+ injectBindingRegistry,
+ scopeValidationType(processingEnv),
+ nullableDiagnosticType,
+ contributionBindingFormatter,
+ methodSignatureFormatter,
+ dependencyRequestFormatter,
+ keyFormatter);
+
+ return ImmutableList.<ProcessingStep>of(
+ new MapKeyProcessingStep(messager, types, mapKeyValidator, mapKeyGenerator),
+ new InjectProcessingStep(
+ messager,
+ injectConstructorValidator,
+ injectFieldValidator,
+ injectMethodValidator,
+ provisionBindingFactory,
+ membersInjectionBindingFactory,
+ injectBindingRegistry),
+ new MonitoringModuleProcessingStep(messager, monitoringModuleGenerator),
+ new ModuleProcessingStep(
+ messager,
+ moduleValidator,
+ providesMethodValidator,
+ provisionBindingFactory,
+ factoryGenerator),
+ new ComponentProcessingStep(
+ messager,
+ componentValidator,
+ subcomponentValidator,
+ componentBuilderValidator,
+ subcomponentBuilderValidator,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator),
+ new ProducerModuleProcessingStep(
+ messager,
+ producerModuleValidator,
+ producesMethodValidator,
+ productionBindingFactory,
+ producerFactoryGenerator),
+ new ProductionComponentProcessingStep(
+ messager,
+ productionComponentValidator,
+ productionComponentBuilderValidator,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator));
+ }
+
+ @Override
+ protected void postProcess() {
+ try {
+ injectBindingRegistry.generateSourcesForRequiredBindings(
+ factoryGenerator, membersInjectorGenerator);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(processingEnv.getMessager());
+ }
+ }
+
+ private static final String DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY =
+ "dagger.disableInterComponentScopeValidation";
+
+ private static final String NULLABLE_VALIDATION_KEY = "dagger.nullableValidation";
+
+ private static final String PRIVATE_MEMBER_VALIDATION_TYPE_KEY =
+ "dagger.privateMemberValidation";
+
+ private static final String STATIC_MEMBER_VALIDATION_TYPE_KEY =
+ "dagger.staticMemberValidation";
+
+ private static ValidationType scopeValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
+ ValidationType.ERROR,
+ EnumSet.allOf(ValidationType.class));
+ }
+
+ private static ValidationType nullableValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ NULLABLE_VALIDATION_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static ValidationType privateMemberValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static ValidationType staticMemberValidationType(ProcessingEnvironment processingEnv) {
+ return valueOf(processingEnv,
+ STATIC_MEMBER_VALIDATION_TYPE_KEY,
+ ValidationType.ERROR,
+ EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
+ }
+
+ private static <T extends Enum<T>> T valueOf(ProcessingEnvironment processingEnv, String key,
+ T defaultValue, Set<T> validValues) {
+ Map<String, String> options = processingEnv.getOptions();
+ if (options.containsKey(key)) {
+ try {
+ T type = Enum.valueOf(
+ defaultValue.getDeclaringClass(),
+ Ascii.toUpperCase(options.get(key)));
+ if (!validValues.contains(type)) {
+ throw new IllegalArgumentException(); // let handler below print out good msg.
+ }
+ return type;
+ } catch (IllegalArgumentException e) {
+ processingEnv.getMessager().printMessage(ERROR, "Processor option -A"
+ + key + " may only have the values " + validValues
+ + " (case insensitive), found: " + options.get(key));
+ }
+ }
+ return defaultValue;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java
new file mode 100644
index 0000000..a9e82a8
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+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.Multimap;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Module;
+import dagger.Subcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules;
+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;
+
+/**
+ * Performs superficial validation of the contract of the {@link Component} annotation.
+ *
+ * @author Gregory Kick
+ */
+final class ComponentValidator {
+ private final Elements elements;
+ private final Types types;
+ private final ComponentDescriptor.Kind componentType;
+ private final ModuleValidator moduleValidator;
+ private final ComponentValidator subcomponentValidator;
+ private final BuilderValidator subcomponentBuilderValidator;
+
+ private ComponentValidator(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = ComponentDescriptor.Kind.SUBCOMPONENT;
+ this.moduleValidator = moduleValidator;
+ this.subcomponentValidator = this;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ private ComponentValidator(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ this.elements = elements;
+ this.types = types;
+ this.componentType = ComponentDescriptor.Kind.COMPONENT;
+ this.moduleValidator = moduleValidator;
+ this.subcomponentValidator = subcomponentValidator;
+ this.subcomponentBuilderValidator = subcomponentBuilderValidator;
+ }
+
+ static ComponentValidator createForComponent(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ ComponentValidator subcomponentValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ return new ComponentValidator(elements,
+ types,
+ moduleValidator,
+ subcomponentValidator,
+ subcomponentBuilderValidator);
+ }
+
+ static ComponentValidator createForSubcomponent(Elements elements,
+ Types types,
+ ModuleValidator moduleValidator,
+ BuilderValidator subcomponentBuilderValidator) {
+ return new ComponentValidator(elements,
+ types,
+ moduleValidator,
+ subcomponentBuilderValidator);
+ }
+
+ @AutoValue
+ static abstract class ComponentValidationReport {
+ abstract Set<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(final TypeElement subject,
+ Set<? extends Element> validatedSubcomponents,
+ Set<? extends Element> validatedSubcomponentBuilders) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ if (!subject.getKind().equals(INTERFACE)
+ && !(subject.getKind().equals(CLASS) && subject.getModifiers().contains(ABSTRACT))) {
+ builder.addError(
+ String.format(
+ "@%s may only be applied to an interface or abstract class",
+ componentType.annotationType().getSimpleName()),
+ subject);
+ }
+
+ ImmutableList<DeclaredType> builders =
+ enclosedBuilders(subject, componentType.builderAnnotationType());
+ if (builders.size() > 1) {
+ builder.addError(
+ String.format(ErrorMessages.builderMsgsFor(componentType).moreThanOne(), builders),
+ subject);
+ }
+
+ DeclaredType subjectType = MoreTypes.asDeclared(subject.asType());
+
+ // TODO(gak): This should use Util.findLocalAndInheritedMethods, otherwise
+ // it can return a logical method multiple times (including overrides, etc.)
+ List<? extends Element> members = elements.getAllMembers(subject);
+ Multimap<Element, ExecutableElement> referencedSubcomponents = LinkedHashMultimap.create();
+ for (ExecutableElement method : ElementFilter.methodsIn(members)) {
+ if (method.getModifiers().contains(ABSTRACT)) {
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(subjectType, method));
+ List<? extends TypeMirror> parameterTypes = resolvedMethod.getParameterTypes();
+ List<? extends VariableElement> parameters = method.getParameters();
+ TypeMirror returnType = resolvedMethod.getReturnType();
+
+ // 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 =
+ checkForAnnotation(returnType, Subcomponent.class);
+ Optional<AnnotationMirror> subcomponentBuilderAnnotation =
+ checkForAnnotation(returnType, Subcomponent.Builder.class);
+ if (subcomponentAnnotation.isPresent()) {
+ referencedSubcomponents.put(MoreTypes.asElement(returnType), method);
+ validateSubcomponentMethod(builder,
+ method,
+ parameters,
+ parameterTypes,
+ returnType,
+ subcomponentAnnotation);
+ } else if (subcomponentBuilderAnnotation.isPresent()) {
+ referencedSubcomponents.put(MoreTypes.asElement(returnType).getEnclosingElement(),
+ method);
+ validateSubcomponentBuilderMethod(builder,
+ method,
+ parameters,
+ returnType,
+ validatedSubcomponentBuilders);
+ } else {
+ // if it's not a subcomponent...
+ switch (parameters.size()) {
+ case 0:
+ // no parameters means that it is a provision method
+ // basically, there are no restrictions here. \o/
+ break;
+ case 1:
+ // one parameter means that it's a members injection method
+ TypeMirror onlyParameter = Iterables.getOnlyElement(parameterTypes);
+ if (!(returnType.getKind().equals(VOID)
+ || types.isSameType(returnType, onlyParameter))) {
+ builder.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...
+ builder.addError(
+ "This method isn't a valid provision method, members injection method or "
+ + "subcomponent factory method. Dagger cannot implement this method",
+ method);
+ break;
+ }
+ }
+ }
+ }
+
+ for (Map.Entry<Element, Collection<ExecutableElement>> entry :
+ referencedSubcomponents.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ builder.addError(
+ String.format(
+ ErrorMessages.SubcomponentBuilderMessages.INSTANCE.moreThanOneRefToSubcomponent(),
+ entry.getKey(),
+ entry.getValue()),
+ subject);
+ }
+ }
+
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(subject, componentType.annotationType()).get();
+ ImmutableList<TypeMirror> moduleTypes = getComponentModules(componentMirror);
+ moduleValidator.validateReferencedModules(subject, builder, moduleTypes);
+
+ // 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 = subcomponentValidator.validate(
+ MoreElements.asType(subcomponent), validatedSubcomponents, validatedSubcomponentBuilders);
+ builder.addItems(subreport.report().items());
+ allSubcomponents.addAll(subreport.referencedSubcomponents());
+ }
+
+ return new AutoValue_ComponentValidator_ComponentValidationReport(allSubcomponents.build(),
+ builder.build());
+ }
+
+ private void validateSubcomponentMethod(final ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method,
+ List<? extends VariableElement> parameters,
+ List<? extends TypeMirror> parameterTypes,
+ TypeMirror returnType,
+ Optional<AnnotationMirror> subcomponentAnnotation) {
+ ImmutableSet<TypeElement> moduleTypes =
+ MoreTypes.asTypeElements(getComponentModules(subcomponentAnnotation.get()));
+
+ // 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.absent();
+ }
+
+ @Override public Optional<TypeElement> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.isAnnotationPresent(t.asElement(), Module.class)
+ ? Optional.of(MoreTypes.asTypeElement(t))
+ : Optional.<TypeElement>absent();
+ }
+ }, null);
+ if (moduleType.isPresent()) {
+ if (variableTypes.contains(moduleType.get())) {
+ builder.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())) {
+ builder.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 {
+ builder.addError(
+ String.format(
+ "Subcomponent factory methods may only accept modules, but %s is not.",
+ parameterType),
+ parameter);
+ }
+ }
+ }
+
+ private void validateSubcomponentBuilderMethod(ValidationReport.Builder<TypeElement> builder,
+ ExecutableElement method, List<? extends VariableElement> parameters, TypeMirror returnType,
+ Set<? extends Element> validatedSubcomponentBuilders) {
+
+ if (!parameters.isEmpty()) {
+ builder.addError(
+ ErrorMessages.SubcomponentBuilderMessages.INSTANCE.builderMethodRequiresNoArgs(), method);
+ }
+
+ // If we haven't already validated the subcomponent builder itself, validate it now.
+ TypeElement builderElement = MoreTypes.asTypeElement(returnType);
+ if (!validatedSubcomponentBuilders.contains(builderElement)) {
+ // TODO(sameb): The builder 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.
+ builder.addItems(subcomponentBuilderValidator.validate(builderElement).items());
+ }
+ }
+
+ private Optional<AnnotationMirror> checkForAnnotation(TypeMirror type,
+ final Class<? extends Annotation> annotation) {
+ return type.accept(new SimpleTypeVisitor6<Optional<AnnotationMirror>, Void>() {
+ @Override
+ protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.getAnnotationMirror(t.asElement(), annotation);
+ }
+ }, null);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
new file mode 100644
index 0000000..5221cf0
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ComponentWriter.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Predicate;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import javax.annotation.Generated;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Creates the implementation class for a component.
+ */
+class ComponentWriter extends AbstractComponentWriter {
+
+ ComponentWriter(
+ Types types,
+ Elements elements,
+ Key.Factory keyFactory,
+ Kind nullableValidationType,
+ ClassName name,
+ BindingGraph graph) {
+ super(types, elements, keyFactory, nullableValidationType, name, graph);
+ }
+
+ @Override
+ protected ClassWriter createComponentClass() {
+ JavaWriter javaWriter = JavaWriter.inPackage(name.packageName());
+ javaWriters.add(javaWriter);
+
+ ClassWriter componentWriter = javaWriter.addClass(name.simpleName());
+ componentWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getCanonicalName());
+ componentWriter.addModifiers(PUBLIC, FINAL);
+ componentWriter.setSupertype(componentDefinitionType());
+ return componentWriter;
+ }
+
+ @Override
+ protected ClassWriter createBuilder() {
+ ClassWriter builderWriter = componentWriter.addNestedClass("Builder");
+ builderWriter.addModifiers(STATIC);
+
+ // Only top-level components have the factory builder() method.
+ // Mirror the user's builder API type if they had one.
+ MethodWriter builderFactoryMethod =
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? componentWriter.addMethod(
+ graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .builderDefinitionType()
+ .asType(),
+ "builder")
+ : componentWriter.addMethod(builderWriter, "builder");
+ builderFactoryMethod.addModifiers(PUBLIC, STATIC);
+ builderFactoryMethod.body().addSnippet("return new %s();", builderWriter.name());
+ return builderWriter;
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ if (canInstantiateAllRequirements()) {
+ MethodWriter factoryMethod =
+ componentWriter.addMethod(componentDefinitionTypeName(), "create");
+ factoryMethod.addModifiers(PUBLIC, STATIC);
+ // TODO(gak): replace this with something that doesn't allocate a builder
+ factoryMethod
+ .body()
+ .addSnippet(
+ "return builder().%s();",
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .buildMethod()
+ .getSimpleName()
+ : "build");
+ }
+ }
+
+ /** {@code true} if all of the graph's required dependencies can be automatically constructed. */
+ private boolean canInstantiateAllRequirements() {
+ return Iterables.all(
+ graph.componentRequirements(),
+ new Predicate<TypeElement>() {
+ @Override
+ public boolean apply(TypeElement dependency) {
+ return componentCanMakeNewInstances(dependency);
+ }
+ });
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
new file mode 100644
index 0000000..50e3435
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+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.Subcomponent;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+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;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility methods related to dagger configuration annotations (e.g.: {@link Component}
+ * and {@link Module}).
+ *
+ * @author Gregory Kick
+ */
+final class ConfigurationAnnotations {
+
+ static boolean isComponent(TypeElement componentDefinitionType) {
+ return MoreElements.isAnnotationPresent(componentDefinitionType, Component.class)
+ || MoreElements.isAnnotationPresent(componentDefinitionType, ProductionComponent.class);
+ }
+
+ private static final String MODULES_ATTRIBUTE = "modules";
+
+ static ImmutableList<TypeMirror> getComponentModules(AnnotationMirror componentAnnotation) {
+ checkNotNull(componentAnnotation);
+ return convertClassArrayToListOfTypes(componentAnnotation, MODULES_ATTRIBUTE);
+ }
+
+ private static final String DEPENDENCIES_ATTRIBUTE = "dependencies";
+
+ static ImmutableList<TypeMirror> getComponentDependencies(AnnotationMirror componentAnnotation) {
+ checkNotNull(componentAnnotation);
+ return convertClassArrayToListOfTypes(componentAnnotation, DEPENDENCIES_ATTRIBUTE);
+ }
+
+ private static final String INCLUDES_ATTRIBUTE = "includes";
+
+ static ImmutableList<TypeMirror> getModuleIncludes(AnnotationMirror moduleAnnotation) {
+ checkNotNull(moduleAnnotation);
+ return convertClassArrayToListOfTypes(moduleAnnotation, INCLUDES_ATTRIBUTE);
+ }
+
+ private static final String INJECTS_ATTRIBUTE = "injects";
+
+ static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
+ checkNotNull(moduleAnnotation);
+ return convertClassArrayToListOfTypes(moduleAnnotation, INJECTS_ATTRIBUTE);
+ }
+
+ /** Returns the first type that specifies this' nullability, or absent if none. */
+ static Optional<DeclaredType> getNullableType(Element element) {
+ List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
+ for (AnnotationMirror mirror : mirrors) {
+ if (mirror.getAnnotationType().asElement().getSimpleName().toString().equals("Nullable")) {
+ return Optional.of(mirror.getAnnotationType());
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Extracts the list of types that is the value of the annotation member {@code elementName} of
+ * {@code annotationMirror}.
+ *
+ * @throws IllegalArgumentException if no such member exists on {@code annotationMirror}, or it
+ * exists but is not an array
+ * @throws TypeNotPresentException if any of the values cannot be converted to a type
+ */
+ static ImmutableList<TypeMirror> convertClassArrayToListOfTypes(
+ AnnotationMirror annotationMirror, String elementName) {
+ return TO_LIST_OF_TYPES.visit(getAnnotationValue(annotationMirror, elementName), elementName);
+ }
+
+ private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, String> TO_LIST_OF_TYPES =
+ new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, String>() {
+ @Override
+ public ImmutableList<TypeMirror> visitArray(
+ List<? extends AnnotationValue> vals, String elementName) {
+ return FluentIterable.from(vals)
+ .transform(
+ new Function<AnnotationValue, TypeMirror>() {
+ @Override
+ public TypeMirror apply(AnnotationValue typeValue) {
+ return TO_TYPE.visit(typeValue);
+ }
+ })
+ .toList();
+ }
+
+ @Override
+ protected ImmutableList<TypeMirror> defaultAction(Object o, String elementName) {
+ throw new IllegalArgumentException(elementName + " is not an array: " + o);
+ }
+ };
+
+ private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE =
+ new SimpleAnnotationValueVisitor6<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 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#transitiveModules}.
+ */
+ @Deprecated
+ static ImmutableSet<TypeElement> getTransitiveModules(
+ Types types, Elements elements, Iterable<TypeElement> seedModules) {
+ TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
+ Queue<TypeElement> moduleQueue = new ArrayDeque<>();
+ Iterables.addAll(moduleQueue, seedModules);
+ Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
+ for (TypeElement moduleElement = moduleQueue.poll();
+ moduleElement != null;
+ moduleElement = moduleQueue.poll()) {
+ Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(moduleElement, Module.class)
+ .or(getAnnotationMirror(moduleElement, ProducerModule.class));
+ if (moduleMirror.isPresent()) {
+ ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder = ImmutableSet.builder();
+ moduleDependenciesBuilder.addAll(
+ MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
+ // (note: we don't recurse 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 elements annotated with the given annotation type. */
+ static ImmutableList<DeclaredType> enclosedBuilders(TypeElement typeElement,
+ final Class<? extends Annotation> annotation) {
+ final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
+ for (TypeElement element : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
+ if (MoreElements.isAnnotationPresent(element, annotation)) {
+ builders.add(MoreTypes.asDeclared(element.asType()));
+ }
+ }
+ return builders.build();
+ }
+
+ static boolean isSubcomponentType(TypeMirror type) {
+ return type.accept(new SubcomponentDetector(), null).isPresent();
+ }
+
+ private static final class SubcomponentDetector
+ extends SimpleTypeVisitor6<Optional<AnnotationMirror>, Void> {
+ @Override
+ protected Optional<AnnotationMirror> defaultAction(TypeMirror e, Void p) {
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
+ return MoreElements.getAnnotationMirror(t.asElement(), Subcomponent.class);
+ }
+ }
+
+ /** Traverses includes from superclasses and adds them into the builder. */
+ private static void addIncludesFromSuperclasses(Types 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));
+ Optional<AnnotationMirror> moduleMirror = getAnnotationMirror(element, Module.class)
+ .or(getAnnotationMirror(element, ProducerModule.class));
+ if (moduleMirror.isPresent()) {
+ builder.addAll(MoreTypes.asTypeElements(getModuleIncludes(moduleMirror.get())));
+ }
+ superclass = element.getSuperclass();
+ }
+ }
+
+ private ConfigurationAnnotations() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java
new file mode 100644
index 0000000..831943f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ContributionBinding.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Component;
+import dagger.MapKey;
+import dagger.Provides;
+import dagger.producers.Produces;
+import dagger.producers.ProductionComponent;
+import java.util.EnumSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MapKeys.unwrapValue;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * An abstract class for a value object representing the mechanism by which a {@link Key} can be
+ * contributed to a dependency graph.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+abstract class ContributionBinding extends Binding {
+
+ @Override
+ Set<DependencyRequest> implicitDependencies() {
+ // Optimization: If we don't need the memberInjectionRequest, don't create more objects.
+ if (!membersInjectionRequest().isPresent()) {
+ return dependencies();
+ } else {
+ // Optimization: Avoid creating an ImmutableSet+Builder just to union two things together.
+ return Sets.union(membersInjectionRequest().asSet(), dependencies());
+ }
+ }
+
+ static enum ContributionType {
+ /** Represents map bindings. */
+ MAP,
+ /** Represents set bindings. */
+ SET,
+ /** Represents a valid non-collection binding. */
+ UNIQUE;
+
+ boolean isMultibinding() {
+ return !this.equals(UNIQUE);
+ }
+ }
+
+ ContributionType contributionType() {
+ switch (provisionType()) {
+ case SET:
+ case SET_VALUES:
+ return ContributionType.SET;
+ case MAP:
+ return ContributionType.MAP;
+ case UNIQUE:
+ return ContributionType.UNIQUE;
+ default:
+ throw new AssertionError("Unknown provision type: " + provisionType());
+ }
+ }
+
+ /** Returns the type that specifies this' nullability, absent if not nullable. */
+ abstract Optional<DeclaredType> nullableType();
+
+ /**
+ * If this is a provision request from an {@code @Provides} or {@code @Produces} method, this will
+ * be the element that contributed it. In the case of subclassed modules, this may differ than the
+ * binding's enclosed element, as this will return the subclass whereas the enclosed element will
+ * be the superclass.
+ */
+ abstract Optional<TypeElement> contributedBy();
+
+ /**
+ * Returns whether this binding is synthetic, i.e., not explicitly tied to code, but generated
+ * implicitly by the framework.
+ */
+ boolean isSyntheticBinding() {
+ return bindingKind().equals(Kind.SYNTHETIC);
+ }
+
+ /** If this provision requires members injection, this will be the corresponding request. */
+ abstract Optional<DependencyRequest> membersInjectionRequest();
+
+ /**
+ * The kind of contribution this binding represents. Defines which elements can specify this kind
+ * of contribution.
+ */
+ enum Kind {
+ /**
+ * A binding that is not explicitly tied to an element, but generated implicitly by the
+ * framework.
+ */
+ SYNTHETIC,
+
+ // Provision kinds
+
+ /** An {@link Inject}-annotated constructor. */
+ INJECTION,
+
+ /** A {@link Provides}-annotated method. */
+ PROVISION,
+
+ /** An implicit binding to a {@link Component @Component}-annotated type. */
+ COMPONENT,
+
+ /** A provision method on a component's {@linkplain Component#dependencies() dependency}. */
+ COMPONENT_PROVISION,
+
+ /**
+ * A subcomponent builder method on a component or subcomponent.
+ */
+ SUBCOMPONENT_BUILDER,
+
+ // Production kinds
+
+ /** A {@link Produces}-annotated method that doesn't return a {@link ListenableFuture}. */
+ IMMEDIATE,
+
+ /** A {@link Produces}-annotated method that returns a {@link ListenableFuture}. */
+ FUTURE_PRODUCTION,
+
+ /**
+ * A production method on a production component's
+ * {@linkplain ProductionComponent#dependencies() dependency} that returns a
+ * {@link ListenableFuture}. Methods on production component dependencies that don't return a
+ * {@link ListenableFuture} are considered {@linkplain #PROVISION provision bindings}.
+ */
+ COMPONENT_PRODUCTION,
+ }
+
+ /**
+ * The kind of this contribution binding.
+ */
+ protected abstract Kind bindingKind();
+
+ /**
+ * A predicate that passes for bindings of a given kind.
+ */
+ static Predicate<ContributionBinding> isOfKind(final Kind kind) {
+ return new Predicate<ContributionBinding>() {
+ @Override
+ public boolean apply(ContributionBinding binding) {
+ return binding.bindingKind().equals(kind);
+ }};
+ }
+
+ /** The provision type that was used to bind the key. */
+ abstract Provides.Type provisionType();
+
+ /**
+ * The strategy for getting an instance of a factory for a {@link ContributionBinding}.
+ */
+ enum FactoryCreationStrategy {
+ /** The factory class is an enum with one value named {@code INSTANCE}. */
+ ENUM_INSTANCE,
+ /** The factory must be created by calling the constructor. */
+ CLASS_CONSTRUCTOR,
+ }
+
+ /**
+ * Returns {@link FactoryCreationStrategy#ENUM_INSTANCE} if the binding has no dependencies and
+ * is a static provision binding or an {@link Inject @Inject} constructor binding. Otherwise
+ * returns {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR}.
+ */
+ FactoryCreationStrategy factoryCreationStrategy() {
+ switch (bindingKind()) {
+ case PROVISION:
+ return implicitDependencies().isEmpty() && bindingElement().getModifiers().contains(STATIC)
+ ? FactoryCreationStrategy.ENUM_INSTANCE
+ : FactoryCreationStrategy.CLASS_CONSTRUCTOR;
+
+ case INJECTION:
+ return implicitDependencies().isEmpty()
+ ? FactoryCreationStrategy.ENUM_INSTANCE
+ : FactoryCreationStrategy.CLASS_CONSTRUCTOR;
+
+ default:
+ return FactoryCreationStrategy.CLASS_CONSTRUCTOR;
+ }
+ }
+
+ /**
+ * Returns the {@link ContributionType}s represented by a given {@link ContributionBinding}
+ * collection.
+ */
+ static <B extends ContributionBinding>
+ ImmutableListMultimap<ContributionType, B> contributionTypesFor(
+ Iterable<? extends B> bindings) {
+ ImmutableListMultimap.Builder<ContributionType, B> builder = ImmutableListMultimap.builder();
+ builder.orderKeysBy(Ordering.<ContributionType>natural());
+ for (B binding : bindings) {
+ builder.put(binding.contributionType(), binding);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns a single {@link ContributionType} represented by a given collection of
+ * {@link ContributionBinding}s.
+ *
+ * @throws IllegalArgumentException if the given bindings are not all of one type
+ */
+ static ContributionType contributionTypeFor(Iterable<ContributionBinding> bindings) {
+ checkNotNull(bindings);
+ checkArgument(!Iterables.isEmpty(bindings), "no bindings");
+ Set<ContributionType> types = EnumSet.noneOf(ContributionType.class);
+ for (ContributionBinding binding : bindings) {
+ types.add(binding.contributionType());
+ }
+ if (types.size() > 1) {
+ throw new IllegalArgumentException(
+ String.format(ErrorMessages.MULTIPLE_CONTRIBUTION_TYPES_FORMAT, types));
+ }
+ return Iterables.getOnlyElement(types);
+ }
+
+ /**
+ * Indexes map-multibindings by map key (the result of calling
+ * {@link AnnotationValue#getValue()} on a single member or the whole {@link AnnotationMirror}
+ * itself, depending on {@link MapKey#unwrapValue()}).
+ */
+ static ImmutableSetMultimap<Object, ContributionBinding> indexMapBindingsByMapKey(
+ Set<ContributionBinding> mapBindings) {
+ return ImmutableSetMultimap.copyOf(
+ Multimaps.index(
+ mapBindings,
+ new Function<ContributionBinding, Object>() {
+ @Override
+ public Object apply(ContributionBinding mapBinding) {
+ AnnotationMirror mapKey = getMapKey(mapBinding.bindingElement()).get();
+ Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
+ return unwrappedValue.isPresent() ? unwrappedValue.get().getValue() : mapKey;
+ }
+ }));
+ }
+
+ /**
+ * Indexes map-multibindings by map key annotation type.
+ */
+ static ImmutableSetMultimap<Wrapper<DeclaredType>, ContributionBinding>
+ indexMapBindingsByAnnotationType(Set<ContributionBinding> mapBindings) {
+ return ImmutableSetMultimap.copyOf(
+ Multimaps.index(
+ mapBindings,
+ new Function<ContributionBinding, Equivalence.Wrapper<DeclaredType>>() {
+ @Override
+ public Equivalence.Wrapper<DeclaredType> apply(ContributionBinding mapBinding) {
+ return MoreTypes.equivalence()
+ .wrap(getMapKey(mapBinding.bindingElement()).get().getAnnotationType());
+ }
+ }));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ContributionBindingFormatter.java b/compiler/src/main/java/dagger/internal/codegen/ContributionBindingFormatter.java
new file mode 100644
index 0000000..0d26761
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ContributionBindingFormatter.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Optional;
+
+import static com.google.auto.common.MoreElements.asExecutable;
+import static com.google.auto.common.MoreTypes.asDeclared;
+
+/**
+ * Formats a {@link ContributionBinding} into a {@link String} suitable for use in error messages.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class ContributionBindingFormatter extends Formatter<ContributionBinding> {
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ ContributionBindingFormatter(MethodSignatureFormatter methodSignatureFormatter) {
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ @Override public String format(ContributionBinding binding) {
+ switch (binding.bindingKind()) {
+ case COMPONENT_PROVISION:
+ case COMPONENT_PRODUCTION:
+ return methodSignatureFormatter.format(asExecutable(binding.bindingElement()));
+
+ case PROVISION:
+ case SUBCOMPONENT_BUILDER:
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return methodSignatureFormatter.format(
+ asExecutable(binding.bindingElement()),
+ Optional.of(asDeclared(binding.contributedBy().get().asType())));
+
+ default:
+ throw new UnsupportedOperationException(
+ "Not yet supporting " + binding.bindingKind() + " binding types.");
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java
new file mode 100644
index 0000000..49fcd9c
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Provides;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducer;
+import java.util.List;
+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.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+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 javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.util.ElementFilter.constructorsIn;
+
+/**
+ * Represents a request for a key at an injection point. Parameters to {@link Inject} constructors
+ * or {@link Provides} methods are examples of key requests.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+// TODO(gak): Set bindings and the permutations thereof need to be addressed
+@AutoValue
+abstract class DependencyRequest {
+ static final Function<DependencyRequest, BindingKey> BINDING_KEY_FUNCTION =
+ new Function<DependencyRequest, BindingKey>() {
+ @Override public BindingKey apply(DependencyRequest request) {
+ return request.bindingKey();
+ }
+ };
+
+ enum Kind {
+ /** A default request for an instance. E.g.: {@code Blah} */
+ INSTANCE,
+ /** A request for a {@link Provider}. E.g.: {@code Provider<Blah>} */
+ PROVIDER,
+ /** A request for a {@link Lazy}. E.g.: {@code Lazy<Blah>} */
+ LAZY,
+ /** A request for a {@link MembersInjector}. E.g.: {@code MembersInjector<Blah>} */
+ MEMBERS_INJECTOR,
+ /** A request for a {@link Producer}. E.g.: {@code Producer<Blah>} */
+ PRODUCER,
+ /** A request for a {@link Produced}. E.g.: {@code Produced<Blah>} */
+ PRODUCED,
+ /**
+ * A request for a {@link ListenableFuture}. E.g.: {@code ListenableFuture<Blah>}.
+ * These can only be requested by component interfaces.
+ */
+ FUTURE,
+ }
+
+ abstract Kind kind();
+ abstract Key key();
+
+ BindingKey bindingKey() {
+ switch (kind()) {
+ case INSTANCE:
+ case LAZY:
+ case PROVIDER:
+ case PRODUCER:
+ case PRODUCED:
+ case FUTURE:
+ return BindingKey.create(BindingKey.Kind.CONTRIBUTION, key());
+ case MEMBERS_INJECTOR:
+ return BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key());
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ abstract Element requestElement();
+
+ /**
+ * Returns the possibly resolved type that contained the requesting element. For members injection
+ * requests, this is the type itself.
+ */
+ abstract DeclaredType enclosingType();
+
+ /** Returns true if this request allows null objects. */
+ abstract boolean isNullable();
+
+ /**
+ * An optional name for this request when it's referred to in generated code. If absent, it will
+ * use a name derived from {@link #requestElement}.
+ */
+ abstract Optional<String> overriddenVariableName();
+
+ /**
+ * 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.
+ */
+ static final class Factory {
+ private final Elements elements;
+ private final Key.Factory keyFactory;
+
+ Factory(Elements elements, Key.Factory keyFactory) {
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ }
+
+ ImmutableSet<DependencyRequest> forRequiredResolvedVariables(DeclaredType container,
+ 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(container, variables.get(i), resolvedTypes.get(i)));
+ }
+ return builder.build();
+ }
+
+ ImmutableSet<DependencyRequest> forRequiredVariables(
+ List<? extends VariableElement> variables) {
+ return FluentIterable.from(variables)
+ .transform(
+ new Function<VariableElement, DependencyRequest>() {
+ @Override
+ public DependencyRequest apply(VariableElement input) {
+ return forRequiredVariable(input);
+ }
+ })
+ .toSet();
+ }
+
+ /**
+ * Creates a implicit {@link DependencyRequest} for {@code mapOfFactoryKey}, which will be used
+ * to satisfy the {@code mapOfValueRequest}.
+ *
+ * @param mapOfValueRequest a request for {@code Map<K, V>}
+ * @param mapOfFactoryKey a key equivalent to {@code mapOfValueRequest}'s key, whose type is
+ * {@code Map<K, Provider<V>>} or {@code Map<K, Producer<V>>}
+ */
+ DependencyRequest forImplicitMapBinding(
+ DependencyRequest mapOfValueRequest, Key mapOfFactoryKey) {
+ checkNotNull(mapOfValueRequest);
+ return new AutoValue_DependencyRequest(
+ Kind.PROVIDER,
+ mapOfFactoryKey,
+ mapOfValueRequest.requestElement(),
+ mapOfValueRequest.enclosingType(),
+ false /* doesn't allow null */,
+ Optional.<String>absent());
+ }
+
+ DependencyRequest forRequiredVariable(VariableElement variableElement) {
+ return forRequiredVariable(variableElement, Optional.<String>absent());
+ }
+
+ DependencyRequest forRequiredVariable(VariableElement variableElement, Optional<String> name) {
+ checkNotNull(variableElement);
+ TypeMirror type = variableElement.asType();
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
+ return newDependencyRequest(
+ variableElement, type, qualifier, getEnclosingType(variableElement), name);
+ }
+
+ DependencyRequest forRequiredResolvedVariable(DeclaredType container,
+ VariableElement variableElement,
+ TypeMirror resolvedType) {
+ checkNotNull(variableElement);
+ checkNotNull(resolvedType);
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
+ return newDependencyRequest(
+ variableElement, resolvedType, qualifier, container, Optional.<String>absent());
+ }
+
+ 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,
+ getEnclosingType(provisionMethod),
+ Optional.<String>absent());
+ }
+
+ 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);
+ DeclaredType container = getEnclosingType(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 new AutoValue_DependencyRequest(
+ Kind.FUTURE,
+ keyFactory.forQualifiedType(
+ qualifier, Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments())),
+ productionMethod,
+ container,
+ false /* doesn't allow null */,
+ Optional.<String>absent());
+ } else {
+ return newDependencyRequest(
+ productionMethod, type, qualifier, container, Optional.<String>absent());
+ }
+ }
+
+ DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod,
+ ExecutableType membersInjectionMethodType) {
+ checkNotNull(membersInjectionMethod);
+ checkNotNull(membersInjectionMethodType);
+ Optional<AnnotationMirror> qualifier =
+ InjectionAnnotations.getQualifier(membersInjectionMethod);
+ checkArgument(!qualifier.isPresent());
+ TypeMirror returnType = membersInjectionMethodType.getReturnType();
+ if (returnType.getKind().equals(DECLARED)
+ && MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
+ return new AutoValue_DependencyRequest(
+ Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(
+ Iterables.getOnlyElement(((DeclaredType) returnType).getTypeArguments())),
+ membersInjectionMethod,
+ getEnclosingType(membersInjectionMethod),
+ false /* doesn't allow null */,
+ Optional.<String>absent());
+ } else {
+ return new AutoValue_DependencyRequest(
+ Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(
+ Iterables.getOnlyElement(membersInjectionMethodType.getParameterTypes())),
+ membersInjectionMethod,
+ getEnclosingType(membersInjectionMethod),
+ false /* doesn't allow null */,
+ Optional.<String>absent());
+ }
+ }
+
+ DependencyRequest forMembersInjectedType(DeclaredType type) {
+ return new AutoValue_DependencyRequest(
+ Kind.MEMBERS_INJECTOR,
+ keyFactory.forMembersInjectedType(type),
+ type.asElement(),
+ type,
+ false /* doesn't allow null */,
+ Optional.<String>absent());
+ }
+
+ DependencyRequest forProductionComponentMonitorProvider() {
+ TypeElement element = elements.getTypeElement(AbstractProducer.class.getCanonicalName());
+ for (ExecutableElement constructor : constructorsIn(element.getEnclosedElements())) {
+ if (constructor.getParameters().size() == 2) {
+ // the 2-arg constructor has the appropriate dependency as its first arg
+ return forRequiredVariable(constructor.getParameters().get(0), Optional.of("monitor"));
+ }
+ }
+ throw new AssertionError("expected 2-arg constructor in AbstractProducer");
+ }
+
+ private DependencyRequest newDependencyRequest(
+ Element requestElement,
+ TypeMirror type,
+ Optional<AnnotationMirror> qualifier,
+ DeclaredType container,
+ Optional<String> name) {
+ KindAndType kindAndType = extractKindAndType(type);
+ if (kindAndType.kind().equals(Kind.MEMBERS_INJECTOR)) {
+ checkArgument(!qualifier.isPresent());
+ }
+ // Only instance types can be non-null -- all other requests are wrapped
+ // inside something (e.g, Provider, Lazy, etc..).
+ // TODO(sameb): should Produced/Producer always require non-nullable?
+ boolean allowsNull = !kindAndType.kind().equals(Kind.INSTANCE)
+ || ConfigurationAnnotations.getNullableType(requestElement).isPresent();
+ return new AutoValue_DependencyRequest(
+ kindAndType.kind(),
+ keyFactory.forQualifiedType(qualifier, kindAndType.type()),
+ requestElement,
+ container,
+ allowsNull,
+ name);
+ }
+
+ @AutoValue
+ static abstract class KindAndType {
+ abstract Kind kind();
+ abstract TypeMirror type();
+ }
+
+ /**
+ * Extracts the correct requesting type & kind out a request type. For example, if a user
+ * requests {@code Provider<Foo>}, this will return ({@link Kind#PROVIDER}, {@code Foo}).
+ *
+ * @throws TypeNotPresentException if {@code type}'s kind is {@link TypeKind#ERROR}, which may
+ * mean that the type will be generated in a later round of processing
+ */
+ static KindAndType extractKindAndType(TypeMirror type) {
+ if (type.getKind().equals(TypeKind.ERROR)) {
+ throw new TypeNotPresentException(type.toString(), null);
+ }
+
+ // We must check TYPEVAR explicitly before the below checks because calling
+ // isTypeOf(..) on a TYPEVAR throws an exception (because it can't be
+ // represented as a Class).
+ if (type.getKind().equals(TypeKind.TYPEVAR)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
+ } else if (isTypeOf(Provider.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PROVIDER,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Lazy.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.LAZY,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(MembersInjector.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.MEMBERS_INJECTOR,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Producer.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCER,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else if (isTypeOf(Produced.class, type)) {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCED,
+ Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
+ } else {
+ return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
+ }
+ }
+
+ static DeclaredType getEnclosingType(Element element) {
+ while (!MoreElements.isType(element)) {
+ element = element.getEnclosingElement();
+ }
+ return MoreTypes.asDeclared(element.asType());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java
new file mode 100644
index 0000000..0e5f1f2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestFormatter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.base.Optional;
+import java.util.List;
+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.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ErrorMessages.INDENT;
+
+/**
+ * Formats a {@link DependencyRequest} into a {@link String} suitable for an error message listing
+ * a chain of dependencies.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class DependencyRequestFormatter extends Formatter<DependencyRequest> {
+ private final Types types;
+
+ DependencyRequestFormatter(Types types) {
+ this.types = types;
+ }
+
+ // TODO(cgruber): Sweep this class for TypeMirror.toString() usage and do some preventive format.
+ // TODO(cgruber): consider returning a small structure containing strings to be indented later.
+ @Override public String format(final DependencyRequest request) {
+ Element requestElement = request.requestElement();
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(requestElement);
+ return requestElement.accept(new SimpleElementVisitor6<String, Optional<AnnotationMirror>>(){
+
+ /* Handle component methods */
+ @Override public String visitExecutable(
+ ExecutableElement method, Optional<AnnotationMirror> qualifier) {
+ StringBuilder builder = new StringBuilder(INDENT);
+ if (method.getParameters().isEmpty()) {
+ // some.package.name.MyComponent.myMethod()
+ // [component method with return type: @other.package.Qualifier some.package.name.Foo]
+ appendEnclosingTypeAndMemberName(method, builder).append("()\n")
+ .append(INDENT).append(INDENT).append("[component method with return type: ");
+ if (qualifier.isPresent()) {
+ // TODO(cgruber) use chenying's annotation mirror stringifier
+ builder.append(qualifier.get()).append(' ');
+ }
+ builder.append(method.getReturnType()).append(']');
+ } else {
+ // some.package.name.MyComponent.myMethod(some.package.name.Foo foo)
+ // [component injection method for type: some.package.name.Foo]
+ VariableElement componentMethodParameter = getOnlyElement(method.getParameters());
+ appendEnclosingTypeAndMemberName(method, builder).append("(");
+ appendParameter(componentMethodParameter, componentMethodParameter.asType(), builder);
+ builder.append(")\n");
+ builder.append(INDENT).append(INDENT).append("[component injection method for type: ")
+ .append(componentMethodParameter.asType())
+ .append(']');
+ }
+ return builder.toString();
+ }
+
+ /* Handle injected fields or method/constructor parameter injection. */
+ @Override public String visitVariable(
+ VariableElement variable, Optional<AnnotationMirror> qualifier) {
+ StringBuilder builder = new StringBuilder(INDENT);
+ TypeMirror resolvedVariableType =
+ MoreTypes.asMemberOf(types, request.enclosingType(), variable);
+ if (variable.getKind().equals(ElementKind.PARAMETER)) {
+ // some.package.name.MyClass.myMethod(some.package.name.Foo arg0, some.package.Bar arg1)
+ // [parameter: @other.package.Qualifier some.package.name.Foo arg0]
+ ExecutableElement methodOrConstructor =
+ MoreElements.asExecutable(variable.getEnclosingElement());
+ ExecutableType resolvedMethodOrConstructor = MoreTypes.asExecutable(
+ types.asMemberOf(request.enclosingType(), methodOrConstructor));
+ appendEnclosingTypeAndMemberName(methodOrConstructor, builder).append('(');
+ List<? extends VariableElement> parameters = methodOrConstructor.getParameters();
+ List<? extends TypeMirror> parameterTypes =
+ resolvedMethodOrConstructor.getParameterTypes();
+ checkState(parameters.size() == parameterTypes.size());
+ for (int i = 0; i < parameters.size(); i++) {
+ appendParameter(parameters.get(i), parameterTypes.get(i), builder);
+ if (i != parameters.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ builder.append(")\n").append(INDENT).append(INDENT).append("[parameter: ");
+ } else {
+ // some.package.name.MyClass.myField
+ // [injected field of type: @other.package.Qualifier some.package.name.Foo myField]
+ appendEnclosingTypeAndMemberName(variable, builder).append("\n")
+ .append(INDENT).append(INDENT).append("[injected field of type: ");
+ }
+ if (qualifier.isPresent()) {
+ // TODO(cgruber) use chenying's annotation mirror stringifier
+ builder.append(qualifier.get()).append(' ');
+ }
+ builder.append(resolvedVariableType)
+ .append(' ')
+ .append(variable.getSimpleName())
+ .append(']');
+ return builder.toString();
+ }
+
+ @Override
+ public String visitType(TypeElement e, Optional<AnnotationMirror> p) {
+ return ""; // types by themselves provide no useful information.
+ }
+
+ @Override protected String defaultAction(Element element, Optional<AnnotationMirror> ignore) {
+ throw new IllegalStateException(
+ "Invalid request " + element.getKind() + " element " + element);
+ }
+ }, qualifier);
+ }
+
+ private StringBuilder appendParameter(VariableElement parameter, TypeMirror type,
+ StringBuilder builder) {
+ return builder.append(type).append(' ').append(parameter.getSimpleName());
+ }
+
+ private StringBuilder appendEnclosingTypeAndMemberName(Element member, StringBuilder builder) {
+ TypeElement type = MoreElements.asType(member.getEnclosingElement());
+ return builder.append(type.getQualifiedName())
+ .append('.')
+ .append(member.getSimpleName());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java
new file mode 100644
index 0000000..1dc48fc
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequestMapper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import dagger.MembersInjector;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+/**
+ * A mapper for associating a {@link DependencyRequest} to a framework class, dependent on
+ * the type of code to be generated (e.g., for {@link Provider} or {@link Producer}).
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+abstract class DependencyRequestMapper {
+ abstract Class<?> getFrameworkClass(DependencyRequest request);
+
+ /**
+ * Returns the framework class to use for a collection of requests of the same {@link BindingKey}.
+ * This allows factories to only take a single argument for multiple requests of the same key.
+ */
+ Class<?> getFrameworkClass(Iterable<DependencyRequest> requests) {
+ ImmutableSet<Class<?>> classes = FluentIterable.from(requests)
+ .transform(new Function<DependencyRequest, Class<?>>() {
+ @Override public Class<?> apply(DependencyRequest request) {
+ return getFrameworkClass(request);
+ }
+ })
+ .toSet();
+ if (classes.size() == 1) {
+ return getOnlyElement(classes);
+ } else if (classes.equals(ImmutableSet.of(Producer.class, Provider.class))) {
+ return Provider.class;
+ } else {
+ throw new IllegalStateException("Bad set of framework classes: " + classes);
+ }
+ }
+
+ private static final class MapperForProvider extends DependencyRequestMapper {
+ @Override public Class<?> getFrameworkClass(DependencyRequest request) {
+ switch (request.kind()) {
+ case INSTANCE:
+ case PROVIDER:
+ case LAZY:
+ return Provider.class;
+ case MEMBERS_INJECTOR:
+ return MembersInjector.class;
+ case PRODUCED:
+ case PRODUCER:
+ throw new IllegalArgumentException();
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ static final DependencyRequestMapper FOR_PROVIDER = new MapperForProvider();
+
+ private static final class MapperForProducer extends DependencyRequestMapper {
+ @Override public Class<?> getFrameworkClass(DependencyRequest request) {
+ switch (request.kind()) {
+ case INSTANCE:
+ case PRODUCED:
+ case PRODUCER:
+ return Producer.class;
+ case PROVIDER:
+ case LAZY:
+ return Provider.class;
+ case MEMBERS_INJECTOR:
+ return MembersInjector.class;
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ static final DependencyRequestMapper FOR_PRODUCER = new MapperForProducer();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java b/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java
new file mode 100644
index 0000000..5ba5635
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/DependencyVariableNamer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Ascii;
+import com.google.common.base.Function;
+import dagger.Lazy;
+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.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+//TODO(gak): develop the heuristics to get better names
+final class DependencyVariableNamer implements Function<DependencyRequest, String> {
+ @Override
+ public String apply(DependencyRequest dependency) {
+ if (dependency.overriddenVariableName().isPresent()) {
+ return dependency.overriddenVariableName().get();
+ }
+ String variableName = dependency.requestElement().getSimpleName().toString();
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return variableName;
+ case LAZY:
+ return variableName.startsWith("lazy") && !variableName.equals("lazy")
+ ? Ascii.toLowerCase(variableName.charAt(4)) + variableName.substring(5)
+ : variableName;
+ case PROVIDER:
+ return variableName.endsWith("Provider") && !variableName.equals("Provider")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ case MEMBERS_INJECTOR:
+ return variableName.endsWith("MembersInjector") && !variableName.equals("MembersInjector")
+ ? variableName.substring(0, variableName.length() - 15)
+ : variableName;
+ case PRODUCED:
+ return variableName.startsWith("produced") && !variableName.equals("produced")
+ ? Ascii.toLowerCase(variableName.charAt(8)) + variableName.substring(9)
+ : variableName;
+ case PRODUCER:
+ return variableName.endsWith("Producer") && !variableName.equals("Producer")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ default:
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java
new file mode 100644
index 0000000..1f52aca
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Provides;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * The collection of error messages to be reported back to users.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ErrorMessages {
+ /*
+ * Common constants.
+ */
+ static final String INDENT = " ";
+ static final int DUPLICATE_SIZE_LIMIT = 10;
+
+ /*
+ * JSR-330 errors
+ *
+ * These are errors that are explicitly outlined in the JSR-330 APIs
+ */
+
+ /* constructors */
+ static final String MULTIPLE_INJECT_CONSTRUCTORS =
+ "Types may only contain one @Inject constructor.";
+
+ /* fields */
+ static final String FINAL_INJECT_FIELD = "@Inject fields may not be final";
+
+ /* methods */
+ static final String ABSTRACT_INJECT_METHOD = "Methods with @Inject may not be abstract.";
+ static final String GENERIC_INJECT_METHOD =
+ "Methods with @Inject may not declare type parameters.";
+
+ /* qualifiers */
+ static final String MULTIPLE_QUALIFIERS =
+ "A single injection site may not use more than one @Qualifier.";
+
+ /* scope */
+ static final String MULTIPLE_SCOPES = "A single binding may not declare more than one @Scope.";
+
+ /*
+ * Dagger errors
+ *
+ * These are errors that arise due to restrictions imposed by the dagger implementation.
+ */
+
+ /* constructors */
+ static final String INJECT_ON_PRIVATE_CONSTRUCTOR =
+ "Dagger does not support injection into private constructors";
+ static final String INJECT_CONSTRUCTOR_ON_INNER_CLASS =
+ "@Inject constructors are invalid on inner classes";
+ static final String INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS =
+ "@Inject is nonsense on the constructor of an abstract class";
+ static final String QUALIFIER_ON_INJECT_CONSTRUCTOR =
+ "@Qualifier annotations are not allowed on @Inject constructors.";
+
+ /* fields */
+ static final String PRIVATE_INJECT_FIELD =
+ "Dagger does not support injection into private fields";
+
+ static final String STATIC_INJECT_FIELD =
+ "Dagger does not support injection into static fields";
+
+ /* methods */
+ static final String PRIVATE_INJECT_METHOD =
+ "Dagger does not support injection into private methods";
+
+ static final String STATIC_INJECT_METHOD =
+ "Dagger does not support injection into static methods";
+
+ /* all */
+ static final String INJECT_INTO_PRIVATE_CLASS =
+ "Dagger does not support injection into private classes";
+
+ /*
+ * Configuration errors
+ *
+ * These are errors that relate specifically to the Dagger configuration API (@Module, @Provides,
+ * etc.)
+ */
+ static final String DUPLICATE_BINDINGS_FOR_KEY_FORMAT =
+ "%s is bound multiple times:";
+
+ static String duplicateMapKeysError(String key) {
+ return "The same map key is bound more than once for " + key;
+ }
+
+ static String inconsistentMapKeyAnnotationsError(String key) {
+ return key + " uses more than one @MapKey annotation type";
+ }
+
+ static final String PROVIDES_METHOD_RETURN_TYPE =
+ "@Provides methods must either return a primitive, an array or a declared type.";
+
+ static final String PRODUCES_METHOD_RETURN_TYPE =
+ "@Produces methods must either return a primitive, an array or a declared type, or a"
+ + " ListenableFuture of one of those types.";
+
+ static final String PRODUCES_METHOD_RAW_FUTURE =
+ "@Produces methods cannot return a raw ListenableFuture.";
+
+ static final String BINDING_METHOD_SET_VALUES_RAW_SET =
+ "@%s methods of type set values cannot return a raw Set";
+
+ static final String PROVIDES_METHOD_SET_VALUES_RETURN_SET =
+ "@Provides methods of type set values must return a Set";
+
+ static final String PRODUCES_METHOD_SET_VALUES_RETURN_SET =
+ "@Produces methods of type set values must return a Set or ListenableFuture of Set";
+
+ static final String BINDING_METHOD_MUST_RETURN_A_VALUE =
+ "@%s methods must return a value (not void).";
+
+ static final String BINDING_METHOD_ABSTRACT = "@%s methods cannot be abstract";
+
+ static final String BINDING_METHOD_PRIVATE = "@%s methods cannot be private";
+
+ static final String BINDING_METHOD_TYPE_PARAMETER =
+ "@%s methods may not have type parameters.";
+
+ static final String BINDING_METHOD_NOT_IN_MODULE =
+ "@%s methods can only be present within a @%s";
+
+ static final String BINDING_METHOD_NOT_MAP_HAS_MAP_KEY =
+ "@%s methods of non map type cannot declare a map key";
+
+ static final String BINDING_METHOD_WITH_NO_MAP_KEY =
+ "@%s methods of type map must declare a map key";
+
+ static final String BINDING_METHOD_WITH_MULTIPLE_MAP_KEY =
+ "@%s methods may not have more than one @MapKey-marked annotation";
+
+ static final String BINDING_METHOD_WITH_SAME_NAME =
+ "Cannot have more than one @%s method with the same name in a single module";
+
+ static final String MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT =
+ "Modules with type parameters must be abstract";
+
+ static final String REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT =
+ "%s is listed as a module, but is an abstract class or interface";
+
+ static final String REFERENCED_MODULE_NOT_ANNOTATED =
+ "%s is listed as a module, but is not annotated with %s";
+
+ static final String REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS =
+ "%s is listed as a module, but has type parameters";
+
+ static final String PROVIDES_METHOD_OVERRIDES_ANOTHER =
+ "@%s methods may not override another method. Overrides: %s";
+
+ static final String METHOD_OVERRIDES_PROVIDES_METHOD =
+ "@%s methods may not be overridden in modules. Overrides: %s";
+
+ static final String PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS =
+ "Cannot use more than one @Qualifier on a @Provides or @Produces method";
+
+ /* mapKey errors*/
+ static final String MAPKEY_WITHOUT_MEMBERS =
+ "Map key annotations must have members";
+
+ static final String UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS=
+ "Map key annotations with unwrapped values must have exactly one member";
+
+ static final String UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER =
+ "Map key annotations with unwrapped values cannot use arrays";
+
+ /* collection binding errors */
+ static final String MULTIPLE_CONTRIBUTION_TYPES_FORMAT =
+ "More than one binding present of different types %s";
+
+ static final String MULTIPLE_BINDING_TYPES_FOR_KEY_FORMAT =
+ "%s has incompatible bindings:\n";
+
+ static final String PROVIDER_ENTRY_POINT_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT =
+ "%s is a provision entry-point, which cannot depend on a production.";
+
+ static final String PROVIDER_MAY_NOT_DEPEND_ON_PRODUCER_FORMAT =
+ "%s is a provision, which cannot depend on a production.";
+
+ static final String REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT =
+ "%s cannot be provided without an @Inject constructor or from an @Provides-annotated method.";
+
+ static final String REQUIRES_PROVIDER_FORMAT =
+ "%s cannot be provided without an @Provides-annotated method.";
+
+ static final String REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT =
+ "%s cannot be provided without an @Inject constructor or from an @Provides- or "
+ + "@Produces-annotated method.";
+
+ static final String REQUIRES_PROVIDER_OR_PRODUCER_FORMAT =
+ "%s cannot be provided without an @Provides- or @Produces-annotated method.";
+
+ static final String MEMBERS_INJECTION_DOES_NOT_IMPLY_PROVISION =
+ "This type supports members injection but cannot be implicitly provided.";
+
+ static final String MEMBERS_INJECTION_WITH_RAW_TYPE =
+ "%s has type parameters, cannot members inject the raw type. via:\n%s";
+
+ static final String MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE =
+ "Type parameters must be bounded for members injection. %s required by %s, via:\n%s";
+
+ static final String CONTAINS_DEPENDENCY_CYCLE_FORMAT = "%s.%s() contains a dependency cycle:\n%s";
+
+ static final String MALFORMED_MODULE_METHOD_FORMAT =
+ "Cannot generated a graph because method %s on module %s was malformed";
+
+ static String nullableToNonNullable(String typeName, String bindingString) {
+ return String.format(
+ "%s is not nullable, but is being provided by %s",
+ typeName,
+ bindingString);
+ }
+
+ static final String CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD =
+ "Cannot return null from a non-@Nullable component method";
+
+ static final String CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD =
+ "Cannot return null from a non-@Nullable @Provides method";
+
+ static ComponentBuilderMessages builderMsgsFor(ComponentDescriptor.Kind kind) {
+ switch(kind) {
+ case COMPONENT:
+ return ComponentBuilderMessages.INSTANCE;
+ case SUBCOMPONENT:
+ return SubcomponentBuilderMessages.INSTANCE;
+ case PRODUCTION_COMPONENT:
+ return ProductionComponentBuilderMessages.INSTANCE;
+ default:
+ throw new IllegalStateException(kind.toString());
+ }
+ }
+
+ static class ComponentBuilderMessages {
+ static final ComponentBuilderMessages INSTANCE = new ComponentBuilderMessages();
+
+ protected String process(String s) { return s; }
+
+ /** Errors for component builders. */
+ final String moreThanOne() {
+ return process("@Component has more than one @Component.Builder: %s");
+ }
+
+ final String cxtorOnlyOneAndNoArgs() {
+ return process("@Component.Builder classes must have exactly one constructor,"
+ + " and it must not 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");
+ }
+
+ final String missingBuildMethod() {
+ return process("@Component.Builder types must have exactly one no-args method that "
+ + " returns the @Component type");
+ }
+
+ final String manyMethodsForType() {
+ return process("@Component.Builder types must not have more than one setter method per type,"
+ + " but %s is set by %s");
+ }
+
+ final String extraSetters() {
+ return process(
+ "@Component.Builder has setters for modules or components that aren't required: %s");
+ }
+
+ final String missingSetters() {
+ return process(
+ "@Component.Builder is missing setters for required modules or components: %s");
+ }
+
+ final String twoBuildMethods() {
+ return process("@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Already found: %s");
+ }
+
+ final String inheritedTwoBuildMethods() {
+ return process("@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Found %s and %s");
+ }
+
+ final String buildMustReturnComponentType() {
+ return process(
+ "@Component.Builder methods that have no arguments must return the @Component type");
+ }
+
+ final String inheritedBuildMustReturnComponentType() {
+ return process(
+ "@Component.Builder methods that have no arguments must return the @Component type"
+ + " Inherited method: %s");
+ }
+
+ final String methodsMustTakeOneArg() {
+ return process("@Component.Builder methods must not have more than one argument");
+ }
+
+ final String inheritedMethodsMustTakeOneArg() {
+ return process(
+ "@Component.Builder methods must not have more than one argument. Inherited method: %s");
+ }
+
+ final String methodsMustReturnVoidOrBuilder() {
+ return process("@Component.Builder setter methods must return void, the builder,"
+ + " or a supertype of the builder");
+ }
+
+ final String inheritedMethodsMustReturnVoidOrBuilder() {
+ return process("@Component.Builder setter methods must return void, the builder,"
+ + "or a supertype of the builder. Inherited method: %s");
+ }
+
+ final String methodsMayNotHaveTypeParameters() {
+ return process("@Component.Builder methods must not have type parameters");
+ }
+
+ final String inheritedMethodsMayNotHaveTypeParameters() {
+ return process(
+ "@Component.Builder methods must not have type parameters. Inherited method: %s");
+ }
+ }
+
+ static final class SubcomponentBuilderMessages extends ComponentBuilderMessages {
+ @SuppressWarnings("hiding")
+ static final SubcomponentBuilderMessages INSTANCE = new SubcomponentBuilderMessages();
+
+ @Override protected String process(String s) {
+ return s.replaceAll("component", "subcomponent").replaceAll("Component", "Subcomponent");
+ }
+
+ String builderMethodRequiresNoArgs() {
+ return "Methods returning a @Subcomponent.Builder must have no arguments";
+ }
+
+ String moreThanOneRefToSubcomponent() {
+ return "Only one method can create a given subcomponent. %s is created by: %s";
+ }
+ }
+
+ static final class ProductionComponentBuilderMessages extends ComponentBuilderMessages {
+ @SuppressWarnings("hiding")
+ static final ProductionComponentBuilderMessages INSTANCE =
+ new ProductionComponentBuilderMessages();
+
+ @Override protected String process(String s) {
+ return s.replaceAll("component", "production component")
+ .replaceAll("Component", "ProductionComponent");
+ }
+ }
+
+ /**
+ * A regular expression to match a small list of specific packages deemed to
+ * be unhelpful to display in fully qualified types in error messages.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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) {
+ // Special case this enum's constants since they will be incredibly common.
+ type = type.replace(Provides.Type.class.getCanonicalName() + ".", "");
+
+ // 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();
+ }
+
+ //TODO(cgruber): Extract Formatter and do something less stringy.
+ static String format(AnnotationMirror annotation) {
+ return stripCommonTypePrefixes(annotation.toString());
+ }
+
+ private ErrorMessages() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java
new file mode 100644
index 0000000..a0a48c8
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/FactoryGenerator.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import dagger.MembersInjector;
+import dagger.Provides.Type;
+import dagger.internal.Factory;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.EnumWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.StringLiteral;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeVariableName;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.Provides.Type.SET;
+import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
+import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link Factory} implementations from {@link ProvisionBinding} instances for
+ * {@link Inject} constructors.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+ private final Diagnostic.Kind nullableValidationType;
+
+ FactoryGenerator(Filer filer, DependencyRequestMapper dependencyRequestMapper,
+ Diagnostic.Kind nullableValidationType) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ this.nullableValidationType = nullableValidationType;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProvisionBinding binding) {
+ return generatedClassNameForBinding(binding);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(ProvisionBinding binding) {
+ return ImmutableSet.of(binding.bindingElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(ProvisionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, ProvisionBinding binding) {
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkState(!binding.hasNonDefaultTypeParameters());
+
+ TypeMirror keyType = binding.provisionType().equals(Type.MAP)
+ ? Util.getProvidedValueTypeOfMap(MoreTypes.asDeclared(binding.key().type()))
+ : binding.key().type();
+ TypeName providedTypeName = TypeNames.forTypeMirror(keyType);
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ final TypeWriter factoryWriter;
+ final Optional<ConstructorWriter> constructorWriter;
+ List<TypeVariableName> typeParameters = Lists.newArrayList();
+ for (TypeParameterElement typeParameter : binding.bindingTypeElement().getTypeParameters()) {
+ typeParameters.add(TypeVariableName.fromTypeParameterElement(typeParameter));
+ }
+ switch (binding.factoryCreationStrategy()) {
+ case ENUM_INSTANCE:
+ EnumWriter enumWriter = writer.addEnum(generatedTypeName.simpleName());
+ enumWriter.addConstant("INSTANCE");
+ constructorWriter = Optional.absent();
+ factoryWriter = enumWriter;
+ // If we have type parameters, then remove the parameters from our providedTypeName,
+ // since we'll be implementing an erased version of it.
+ if (!typeParameters.isEmpty()) {
+ factoryWriter.annotate(SuppressWarnings.class).setValue("rawtypes");
+ providedTypeName = ((ParameterizedTypeName) providedTypeName).type();
+ }
+ break;
+ case CLASS_CONSTRUCTOR:
+ ClassWriter classWriter = writer.addClass(generatedTypeName.simpleName());
+ classWriter.addTypeParameters(typeParameters);
+ classWriter.addModifiers(FINAL);
+ constructorWriter = Optional.of(classWriter.addConstructor());
+ constructorWriter.get().addModifiers(PUBLIC);
+ factoryWriter = classWriter;
+ if (binding.bindingKind().equals(PROVISION)
+ && !binding.bindingElement().getModifiers().contains(STATIC)) {
+ TypeName enclosingType = TypeNames.forTypeMirror(binding.bindingTypeElement().asType());
+ factoryWriter.addField(enclosingType, "module").addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(enclosingType, "module");
+ constructorWriter.get().body()
+ .addSnippet("assert module != null;")
+ .addSnippet("this.module = module;");
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ factoryWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ factoryWriter.addModifiers(PUBLIC);
+ factoryWriter.addImplementedType(
+ ParameterizedTypeName.create(ClassName.fromClass(Factory.class), providedTypeName));
+
+ MethodWriter getMethodWriter = factoryWriter.addMethod(providedTypeName, "get");
+ getMethodWriter.annotate(Override.class);
+ getMethodWriter.addModifiers(PUBLIC);
+
+ if (binding.membersInjectionRequest().isPresent()) {
+ ParameterizedTypeName membersInjectorType = ParameterizedTypeName.create(
+ MembersInjector.class, providedTypeName);
+ factoryWriter.addField(membersInjectorType, "membersInjector").addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(membersInjectorType, "membersInjector");
+ constructorWriter.get().body()
+ .addSnippet("assert membersInjector != null;")
+ .addSnippet("this.membersInjector = membersInjector;");
+ }
+
+ ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, binding.dependencies());
+
+ for (FrameworkField bindingField : fields.values()) {
+ TypeName fieldType = bindingField.frameworkType();
+ FieldWriter field = factoryWriter.addField(fieldType, bindingField.name());
+ field.addModifiers(PRIVATE, FINAL);
+ constructorWriter.get().addParameter(field.type(), field.name());
+ constructorWriter.get().body()
+ .addSnippet("assert %s != null;", field.name())
+ .addSnippet("this.%1$s = %1$s;", field.name());
+ }
+
+ // 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.)
+ switch(binding.bindingKind()) {
+ case INJECTION:
+ case PROVISION:
+ // The return type is usually the same as the implementing type, except in the case
+ // of enums with type variables (where we cast).
+ TypeName returnType = ParameterizedTypeName.create(ClassName.fromClass(Factory.class),
+ TypeNames.forTypeMirror(keyType));
+ MethodWriter createMethodWriter = factoryWriter.addMethod(returnType, "create");
+ createMethodWriter.addTypeParameters(typeParameters);
+ createMethodWriter.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
+ Map<String, TypeName> params = constructorWriter.isPresent()
+ ? constructorWriter.get().parameters() : ImmutableMap.<String, TypeName>of();
+ for (Map.Entry<String, TypeName> param : params.entrySet()) {
+ createMethodWriter.addParameter(param.getValue(), param.getKey());
+ }
+ switch (binding.factoryCreationStrategy()) {
+ case ENUM_INSTANCE:
+ if (typeParameters.isEmpty()) {
+ createMethodWriter.body().addSnippet("return INSTANCE;");
+ } else {
+ // We use an unsafe cast here because the types are different.
+ // It's safe because the type is never referenced anywhere.
+ createMethodWriter.annotate(SuppressWarnings.class).setValue("unchecked");
+ createMethodWriter.body().addSnippet("return (Factory) INSTANCE;");
+ }
+ break;
+ case CLASS_CONSTRUCTOR:
+ createMethodWriter.body().addSnippet("return new %s(%s);",
+ parameterizedGeneratedTypeNameForBinding(binding),
+ Joiner.on(", ").join(params.keySet()));
+ break;
+ default:
+ throw new AssertionError();
+ }
+ break;
+ default: // do nothing.
+ }
+
+ List<Snippet> parameters = Lists.newArrayList();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ parameters.add(frameworkTypeUsageStatement(
+ Snippet.format(fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ Snippet parametersSnippet = makeParametersSnippet(parameters);
+
+ if (binding.bindingKind().equals(PROVISION)) {
+ Snippet providesMethodInvocation = Snippet.format("%s.%s(%s)",
+ binding.bindingElement().getModifiers().contains(STATIC)
+ ? ClassName.fromTypeElement(binding.bindingTypeElement())
+ : "module",
+ binding.bindingElement().getSimpleName(),
+ parametersSnippet);
+
+ if (binding.provisionType().equals(SET)) {
+ TypeName paramTypeName = TypeNames.forTypeMirror(
+ MoreTypes.asDeclared(keyType).getTypeArguments().get(0));
+ // TODO(cgruber): only be explicit with the parameter if paramType contains wildcards.
+ getMethodWriter.body().addSnippet("return %s.<%s>singleton(%s);",
+ ClassName.fromClass(Collections.class), paramTypeName, providesMethodInvocation);
+ } else if (binding.nullableType().isPresent()
+ || nullableValidationType.equals(Diagnostic.Kind.WARNING)) {
+ if (binding.nullableType().isPresent()) {
+ getMethodWriter.annotate(
+ (ClassName) TypeNames.forTypeMirror(binding.nullableType().get()));
+ }
+ getMethodWriter.body().addSnippet("return %s;", providesMethodInvocation);
+ } else {
+ StringLiteral failMsg =
+ StringLiteral.forValue(CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD);
+ getMethodWriter.body().addSnippet(Snippet.format(Joiner.on('\n').join(
+ "%s provided = %s;",
+ "if (provided == null) {",
+ " throw new NullPointerException(%s);",
+ "}",
+ "return provided;"),
+ getMethodWriter.returnType(),
+ providesMethodInvocation,
+ failMsg));
+ }
+ } else if (binding.membersInjectionRequest().isPresent()) {
+ getMethodWriter.body().addSnippet("%1$s instance = new %1$s(%2$s);",
+ providedTypeName, parametersSnippet);
+ getMethodWriter.body().addSnippet("membersInjector.injectMembers(instance);");
+ getMethodWriter.body().addSnippet("return instance;");
+ } else {
+ getMethodWriter.body()
+ .addSnippet("return new %s(%s);", providedTypeName, parametersSnippet);
+ }
+
+ // TODO(gak): write a sensible toString
+ return ImmutableSet.of(writer);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Formatter.java b/compiler/src/main/java/dagger/internal/codegen/Formatter.java
new file mode 100644
index 0000000..880b787
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Formatter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Function;
+
+/**
+ * A formatter which transforms an instance of a particular type into a string
+ * representation.
+ *
+ * @param <T> the type of the object to be transformed.
+ * @author Christian Gruber
+ * @since 2.0
+ */
+abstract class Formatter<T> implements Function<T, String> {
+
+ /**
+ * 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(T)} instead. This method exists to make
+ * formatters easy to use when functions are required, but shouldn't be called directly.
+ */
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ @Override final public String apply(T object) {
+ return format(object);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java b/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java
new file mode 100644
index 0000000..38e8f02
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/FrameworkField.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.CaseFormat;
+import com.google.common.collect.ImmutableSet;
+import dagger.MembersInjector;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor6;
+
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
+
+/**
+ * A value object that represents a field used by Dagger-generated code.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+@AutoValue
+abstract class FrameworkField {
+ // TODO(gak): reexamine the this class and how consistently we're using it and its creation
+ // methods
+ static FrameworkField createWithTypeFromKey(
+ Class<?> frameworkClass, BindingKey bindingKey, String name) {
+ String suffix = frameworkClass.getSimpleName();
+ ParameterizedTypeName frameworkType = ParameterizedTypeName.create(
+ ClassName.fromClass(frameworkClass),
+ TypeNames.forTypeMirror(bindingKey.key().type()));
+ return new AutoValue_FrameworkField(frameworkClass, frameworkType, bindingKey,
+ name.endsWith(suffix) ? name : name + suffix);
+ }
+
+ private static FrameworkField createForMapBindingContribution(
+ Class<?> frameworkClass, BindingKey bindingKey, String name) {
+ TypeMirror mapValueType =
+ MoreTypes.asDeclared(bindingKey.key().type()).getTypeArguments().get(1);
+ return new AutoValue_FrameworkField(frameworkClass,
+ (ParameterizedTypeName) TypeNames.forTypeMirror(mapValueType),
+ bindingKey,
+ name);
+ }
+
+ static FrameworkField createForSyntheticContributionBinding(
+ int contributionNumber, ContributionBinding contributionBinding) {
+ switch (contributionBinding.contributionType()) {
+ case MAP:
+ return createForMapBindingContribution(
+ contributionBinding.frameworkClass(),
+ contributionBinding.bindingKey(),
+ KeyVariableNamer.INSTANCE.apply(contributionBinding.key())
+ + "Contribution"
+ + contributionNumber);
+
+ case SET:
+ case UNIQUE:
+ return createWithTypeFromKey(
+ contributionBinding.frameworkClass(),
+ contributionBinding.bindingKey(),
+ KeyVariableNamer.INSTANCE.apply(contributionBinding.key())
+ + "Contribution"
+ + contributionNumber);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ static FrameworkField createForResolvedBindings(ResolvedBindings resolvedBindings) {
+ BindingKey bindingKey = resolvedBindings.bindingKey();
+ switch (bindingKey.kind()) {
+ case CONTRIBUTION:
+ ImmutableSet<ContributionBinding> contributionBindings =
+ resolvedBindings.contributionBindings();
+ switch (contributionTypeFor(contributionBindings)) {
+ case SET:
+ case MAP:
+ return createWithTypeFromKey(
+ FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
+ bindingKey,
+ KeyVariableNamer.INSTANCE.apply(bindingKey.key()));
+ case UNIQUE:
+ ContributionBinding binding = getOnlyElement(contributionBindings);
+ return createWithTypeFromKey(
+ FrameworkField.frameworkClassForResolvedBindings(resolvedBindings),
+ bindingKey,
+ BINDING_ELEMENT_NAME.visit(binding.bindingElement()));
+ default:
+ throw new AssertionError();
+ }
+ case MEMBERS_INJECTION:
+ return createWithTypeFromKey(
+ MembersInjector.class,
+ bindingKey,
+ CaseFormat.UPPER_CAMEL.to(
+ CaseFormat.LOWER_CAMEL,
+ resolvedBindings
+ .membersInjectionBinding()
+ .get()
+ .bindingElement()
+ .getSimpleName()
+ .toString()));
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static final ElementVisitor<String, Void> BINDING_ELEMENT_NAME =
+ new ElementKindVisitor6<String, Void>() {
+ @Override
+ public String visitExecutableAsConstructor(ExecutableElement e, Void p) {
+ return visit(e.getEnclosingElement());
+ }
+
+ @Override
+ public String visitExecutableAsMethod(ExecutableElement e, Void p) {
+ return e.getSimpleName().toString();
+ }
+
+ @Override
+ public String visitType(TypeElement e, Void p) {
+ return CaseFormat.UPPER_CAMEL.to(
+ CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
+ }
+ };
+
+ static Class<?> frameworkClassForResolvedBindings(ResolvedBindings resolvedBindings) {
+ switch (resolvedBindings.bindingKey().kind()) {
+ case CONTRIBUTION:
+ return any(resolvedBindings.contributionBindings(), Binding.Type.PRODUCTION)
+ ? Binding.Type.PRODUCTION.frameworkClass()
+ : Binding.Type.PROVISION.frameworkClass();
+ case MEMBERS_INJECTION:
+ return MembersInjector.class;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ abstract Class<?> frameworkClass();
+ abstract ParameterizedTypeName frameworkType();
+ abstract BindingKey bindingKey();
+ abstract String name();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java b/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java
new file mode 100644
index 0000000..f7ca429
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectBindingRegistry.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+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 dagger.Component;
+import dagger.Provides;
+import dagger.internal.codegen.writer.ClassName;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+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.lang.model.util.Types;
+import javax.tools.Diagnostic.Kind;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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.SourceFiles.generatedClassNameForBinding;
+
+/**
+ * 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.).
+ *
+ * @author Gregory Kick
+ */
+final class InjectBindingRegistry {
+ private final Elements elements;
+ private final Types types;
+ private final Messager messager;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final MembersInjectionBinding.Factory membersInjectionBindingFactory;
+
+ final class BindingsCollection<B extends Binding> {
+ private final Map<Key, B> bindingsByKey = Maps.newLinkedHashMap();
+ private final Deque<B> bindingsRequiringGeneration = new ArrayDeque<>();
+ private final Set<Key> materializedBindingKeys = Sets.newLinkedHashSet();
+
+ void generateBindings(SourceFileGenerator<B> generator) throws SourceFileGenerationException {
+ for (B binding = bindingsRequiringGeneration.poll();
+ binding != null;
+ binding = bindingsRequiringGeneration.poll()) {
+ checkState(!binding.hasNonDefaultTypeParameters());
+ 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, ClassName factoryName, boolean explicit) {
+ tryToCacheBinding(binding);
+ tryToGenerateBinding(binding, factoryName, explicit);
+ }
+
+ /**
+ * 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, ClassName factoryName, boolean explicit) {
+ if (shouldGenerateBinding(binding, factoryName)) {
+ bindingsRequiringGeneration.offer(binding);
+ if (!explicit) {
+ messager.printMessage(Kind.NOTE, String.format(
+ "Generating a MembersInjector or Factory for %s. "
+ + "Prefer to run the dagger processor over that class instead.",
+ 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.hasNonDefaultTypeParameters()
+ && elements.getTypeElement(factoryName.canonicalName()) == null
+ && !materializedBindingKeys.contains(binding.key())
+ && !bindingsRequiringGeneration.contains(binding);
+
+ }
+
+ /** 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.hasNonDefaultTypeParameters()
+ || binding.bindingTypeElement().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<>();
+ private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
+ new BindingsCollection<>();
+
+ InjectBindingRegistry(Elements elements,
+ Types types,
+ Messager messager,
+ ProvisionBinding.Factory provisionBindingFactory,
+ MembersInjectionBinding.Factory membersInjectionBindingFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.messager = messager;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.membersInjectionBindingFactory = membersInjectionBindingFactory;
+ }
+
+ /**
+ * This method ensures that sources for all registered {@link Binding bindings} (either
+ * {@linkplain #registerBinding explicitly} or implicitly via
+ * {@link #getOrFindMembersInjectionBinding} or {@link #getOrFindProvisionBinding}) are generated.
+ */
+ void generateSourcesForRequiredBindings(FactoryGenerator factoryGenerator,
+ MembersInjectorGenerator membersInjectorGenerator) throws SourceFileGenerationException {
+ provisionBindings.generateBindings(factoryGenerator);
+ membersInjectionBindings.generateBindings(membersInjectorGenerator);
+ }
+
+ ProvisionBinding registerBinding(ProvisionBinding binding) {
+ return registerBinding(binding, true);
+ }
+
+ MembersInjectionBinding registerBinding(MembersInjectionBinding binding) {
+ return registerBinding(binding, true);
+ }
+
+ /**
+ * Registers the binding for generation & later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private ProvisionBinding registerBinding(ProvisionBinding binding, boolean explicit) {
+ ClassName factoryName = generatedClassNameForBinding(binding);
+ provisionBindings.tryRegisterBinding(binding, factoryName, explicit);
+ if (binding.hasNonDefaultTypeParameters()) {
+ provisionBindings.tryToGenerateBinding(provisionBindingFactory.unresolve(binding),
+ factoryName, explicit);
+ }
+ return binding;
+ }
+
+ /**
+ * Registers the binding for generation & later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private MembersInjectionBinding registerBinding(
+ MembersInjectionBinding binding, boolean explicit) {
+ ClassName membersInjectorName = generatedClassNameForBinding(binding);
+ membersInjectionBindings.tryRegisterBinding(binding, membersInjectorName, explicit);
+ if (binding.hasNonDefaultTypeParameters()) {
+ membersInjectionBindings.tryToGenerateBinding(
+ membersInjectionBindingFactory.unresolve(binding), membersInjectorName, explicit);
+ }
+ return binding;
+ }
+
+ Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
+ checkNotNull(key);
+ if (!key.isValidImplicitProvisionKey(types)) {
+ return Optional.absent();
+ }
+ 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()));
+ List<ExecutableElement> constructors =
+ ElementFilter.constructorsIn(element.getEnclosedElements());
+ ImmutableSet<ExecutableElement> injectConstructors = FluentIterable.from(constructors)
+ .filter(new Predicate<ExecutableElement>() {
+ @Override public boolean apply(ExecutableElement input) {
+ return isAnnotationPresent(input, Inject.class);
+ }
+ }).toSet();
+ switch (injectConstructors.size()) {
+ case 0:
+ // No constructor found.
+ return Optional.absent();
+ case 1:
+ ProvisionBinding constructorBinding = provisionBindingFactory.forInjectConstructor(
+ Iterables.getOnlyElement(injectConstructors), Optional.of(key.type()));
+ return Optional.of(registerBinding(constructorBinding, false));
+ default:
+ throw new IllegalStateException("Found multiple @Inject constructors: "
+ + injectConstructors);
+ }
+ }
+
+ MembersInjectionBinding getOrFindMembersInjectionBinding(Key key) {
+ checkNotNull(key);
+ // TODO(gak): is checking the kind enough?
+ checkArgument(key.isValidMembersInjectionKey());
+ MembersInjectionBinding binding = membersInjectionBindings.getBinding(key);
+ if (binding != null) {
+ return binding;
+ }
+ return registerBinding(membersInjectionBindingFactory.forInjectedType(
+ MoreTypes.asDeclared(key.type()), Optional.of(key.type())), false);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java
new file mode 100644
index 0000000..11cd066
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectConstructorValidator.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+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;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_INNER_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_INTO_PRIVATE_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_ON_PRIVATE_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_INJECT_CONSTRUCTORS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_SCOPES;
+import static dagger.internal.codegen.ErrorMessages.QUALIFIER_ON_INJECT_CONSTRUCTOR;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.InjectionAnnotations.getScopes;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} constructors.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectConstructorValidator {
+ ValidationReport<TypeElement> validate(ExecutableElement constructorElement) {
+ ValidationReport.Builder<TypeElement> builder =
+ ValidationReport.about(MoreElements.asType(constructorElement.getEnclosingElement()));
+ if (constructorElement.getModifiers().contains(PRIVATE)) {
+ builder.addError(INJECT_ON_PRIVATE_CONSTRUCTOR, constructorElement);
+ }
+
+ for (AnnotationMirror qualifier : getQualifiers(constructorElement)) {
+ builder.addError(QUALIFIER_ON_INJECT_CONSTRUCTOR, constructorElement, qualifier);
+ }
+
+ for (VariableElement parameter : constructorElement.getParameters()) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(parameter);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, constructorElement, qualifier);
+ }
+ }
+ }
+
+ TypeElement enclosingElement =
+ MoreElements.asType(constructorElement.getEnclosingElement());
+ Set<Modifier> typeModifiers = enclosingElement.getModifiers();
+
+ if (typeModifiers.contains(PRIVATE)) {
+ builder.addError(INJECT_INTO_PRIVATE_CLASS, constructorElement);
+ }
+
+ if (typeModifiers.contains(ABSTRACT)) {
+ builder.addError(INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS, constructorElement);
+ }
+
+ if (enclosingElement.getNestingKind().isNested()
+ && !typeModifiers.contains(STATIC)) {
+ builder.addError(INJECT_CONSTRUCTOR_ON_INNER_CLASS, constructorElement);
+ }
+
+ // This is computationally expensive, but probably preferable to a giant index
+ FluentIterable<ExecutableElement> injectConstructors = FluentIterable.from(
+ ElementFilter.constructorsIn(enclosingElement.getEnclosedElements()))
+ .filter(new Predicate<ExecutableElement>() {
+ @Override public boolean apply(ExecutableElement input) {
+ return isAnnotationPresent(input, Inject.class);
+ }
+ });
+
+ if (injectConstructors.size() > 1) {
+ builder.addError(MULTIPLE_INJECT_CONSTRUCTORS, constructorElement);
+ }
+
+ ImmutableSet<? extends AnnotationMirror> scopes = getScopes(enclosingElement);
+ if (scopes.size() > 1) {
+ for (AnnotationMirror scope : scopes) {
+ builder.addError(MULTIPLE_SCOPES, enclosingElement, scope);
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java
new file mode 100644
index 0000000..e30678a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectFieldValidator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.ErrorMessages.FINAL_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_FIELD;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} fields.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectFieldValidator {
+ private Kind privateMemberValidationKind;
+ private Kind staticMemberValidationKind;
+
+ public InjectFieldValidator(
+ Kind privateMemberValidationKind, Kind staticMemberValidationKind) {
+ this.privateMemberValidationKind = privateMemberValidationKind;
+ this.staticMemberValidationKind = staticMemberValidationKind;
+ }
+
+ ValidationReport<VariableElement> validate(VariableElement fieldElement) {
+ ValidationReport.Builder<VariableElement> builder = ValidationReport.about(fieldElement);
+ Set<Modifier> modifiers = fieldElement.getModifiers();
+ if (modifiers.contains(FINAL)) {
+ builder.addError(FINAL_INJECT_FIELD, fieldElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(PRIVATE_INJECT_FIELD, privateMemberValidationKind, fieldElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(STATIC_INJECT_FIELD, staticMemberValidationKind, fieldElement);
+ }
+
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(fieldElement);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, fieldElement, qualifier);
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java
new file mode 100644
index 0000000..a716b7d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectMethodValidator.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+import javax.tools.Diagnostic.Kind;
+
+import static dagger.internal.codegen.ErrorMessages.ABSTRACT_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.GENERIC_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_METHOD;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectMethodValidator {
+ private Kind privateMemberValidationKind;
+ private Kind staticMemberValidationKind;
+
+ public InjectMethodValidator(
+ Kind privateMemberValidationKind, Kind staticMemberValidationKind) {
+ this.privateMemberValidationKind = privateMemberValidationKind;
+ this.staticMemberValidationKind = staticMemberValidationKind;
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement methodElement) {
+ ValidationReport.Builder<ExecutableElement> builder = ValidationReport.about(methodElement);
+ Set<Modifier> modifiers = methodElement.getModifiers();
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(ABSTRACT_INJECT_METHOD, methodElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(PRIVATE_INJECT_METHOD, privateMemberValidationKind, methodElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(STATIC_INJECT_METHOD, staticMemberValidationKind, methodElement);
+ }
+
+ if (!methodElement.getTypeParameters().isEmpty()) {
+ builder.addError(GENERIC_INJECT_METHOD, methodElement);
+ }
+
+ for (VariableElement parameter : methodElement.getParameters()) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(parameter);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(MULTIPLE_QUALIFIERS, methodElement, qualifier);
+ }
+ }
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java
new file mode 100644
index 0000000..dac904f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectProcessingStep.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+import javax.annotation.processing.Messager;
+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.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor6;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the {@link Inject}
+ * annotation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final InjectConstructorValidator constructorValidator;
+ private final InjectFieldValidator fieldValidator;
+ private final InjectMethodValidator methodValidator;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final MembersInjectionBinding.Factory membersInjectionBindingFactory;
+ private final InjectBindingRegistry injectBindingRegistry;
+
+ InjectProcessingStep(
+ Messager messager,
+ InjectConstructorValidator constructorValidator,
+ InjectFieldValidator fieldValidator,
+ InjectMethodValidator methodValidator,
+ ProvisionBinding.Factory provisionBindingFactory,
+ MembersInjectionBinding.Factory membersInjectionBindingFactory,
+ InjectBindingRegistry factoryRegistrar) {
+ this.messager = messager;
+ this.constructorValidator = constructorValidator;
+ this.fieldValidator = fieldValidator;
+ this.methodValidator = methodValidator;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.membersInjectionBindingFactory = membersInjectionBindingFactory;
+ this.injectBindingRegistry = factoryRegistrar;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(Inject.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder();
+ // TODO(gak): add some error handling for bad source files
+ final ImmutableSet.Builder<ProvisionBinding> provisions = ImmutableSet.builder();
+ // TODO(gak): instead, we should collect reports by type and check later
+ final ImmutableSet.Builder<DeclaredType> membersInjectedTypes = ImmutableSet.builder();
+
+ for (Element injectElement : elementsByAnnotation.get(Inject.class)) {
+ try {
+ injectElement.accept(
+ new ElementKindVisitor6<Void, Void>() {
+ @Override
+ public Void visitExecutableAsConstructor(
+ ExecutableElement constructorElement, Void v) {
+ ValidationReport<TypeElement> report =
+ constructorValidator.validate(constructorElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ provisions.add(
+ provisionBindingFactory.forInjectConstructor(
+ constructorElement, Optional.<TypeMirror>absent()));
+ DeclaredType type =
+ MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ if (membersInjectionBindingFactory.hasInjectedMembers(type)) {
+ membersInjectedTypes.add(type);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitVariableAsField(VariableElement fieldElement, Void p) {
+ ValidationReport<VariableElement> report = fieldValidator.validate(fieldElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ membersInjectedTypes.add(
+ MoreTypes.asDeclared(fieldElement.getEnclosingElement().asType()));
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitExecutableAsMethod(ExecutableElement methodElement, Void p) {
+ ValidationReport<ExecutableElement> report =
+ methodValidator.validate(methodElement);
+
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ membersInjectedTypes.add(
+ MoreTypes.asDeclared(methodElement.getEnclosingElement().asType()));
+ }
+
+ return null;
+ }
+ },
+ null);
+ } catch (TypeNotPresentException e) {
+ rejectedElements.add(injectElement);
+ }
+ }
+
+ for (DeclaredType injectedType : membersInjectedTypes.build()) {
+ injectBindingRegistry.registerBinding(membersInjectionBindingFactory.forInjectedType(
+ injectedType, Optional.<TypeMirror>absent()));
+ }
+
+ for (ProvisionBinding binding : provisions.build()) {
+ injectBindingRegistry.registerBinding(binding);
+ }
+ return rejectedElements.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java b/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java
new file mode 100644
index 0000000..b3b245d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/InjectionAnnotations.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.AnnotationMirrors;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import javax.inject.Qualifier;
+import javax.inject.Scope;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utilities relating to annotations defined in the {@code javax.inject} package.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class InjectionAnnotations {
+ static Optional<AnnotationMirror> getScopeAnnotation(Element e) {
+ checkNotNull(e);
+ ImmutableSet<? extends AnnotationMirror> scopeAnnotations = getScopes(e);
+ switch (scopeAnnotations.size()) {
+ case 0:
+ return Optional.absent();
+ case 1:
+ return Optional.<AnnotationMirror>of(scopeAnnotations.iterator().next());
+ default:
+ throw new IllegalArgumentException(
+ e + " was annotated with more than one @Scope annotation");
+ }
+ }
+
+ static Optional<AnnotationMirror> getQualifier(Element e) {
+ checkNotNull(e);
+ ImmutableSet<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
+ switch (qualifierAnnotations.size()) {
+ case 0:
+ return Optional.absent();
+ 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);
+ }
+
+ static ImmutableSet<? extends AnnotationMirror> getScopes(Element element) {
+ return AnnotationMirrors.getAnnotatedAnnotations(element, Scope.class);
+ }
+
+ private InjectionAnnotations() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Key.java b/compiler/src/main/java/dagger/internal/codegen/Key.java
new file mode 100644
index 0000000..f0bd3a0
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Key.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.AnnotationMirrors;
+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.base.MoreObjects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Provides;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.Produces;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+import javax.lang.model.element.AnnotationMirror;
+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.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreTypes.asExecutable;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
+import static dagger.internal.codegen.Util.unwrapOptionalEquivalence;
+import static dagger.internal.codegen.Util.wrapOptionalInEquivalence;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * Represents a unique combination of {@linkplain TypeMirror type} and
+ * {@linkplain Qualifier qualifier} to which binding can occur.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class Key {
+ /**
+ * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
+ * for the type of this key.
+ *
+ * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented
+ * to represent logical equality, so {@link AnnotationMirrors#equivalence()}
+ * provides this facility.
+ */
+ abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier();
+
+ /**
+ * The type represented by this key.
+ *
+ * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent
+ * logical equality, so {@link MoreTypes#equivalence()} wraps this type.
+ */
+ abstract Equivalence.Wrapper<TypeMirror> wrappedType();
+
+ Optional<AnnotationMirror> qualifier() {
+ return unwrapOptionalEquivalence(wrappedQualifier());
+ }
+
+ TypeMirror type() {
+ return wrappedType().get();
+ }
+
+ private static TypeMirror normalize(Types types, TypeMirror type) {
+ TypeKind kind = type.getKind();
+ return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
+ }
+
+ Key withType(Types types, TypeMirror newType) {
+ return new AutoValue_Key(wrappedQualifier(),
+ MoreTypes.equivalence().wrap(normalize(types, newType)));
+ }
+
+ boolean isValidMembersInjectionKey() {
+ return !qualifier().isPresent();
+ }
+
+ /**
+ * Returns true if the key is valid as an implicit key (that is, if it's valid for a just-in-time
+ * binding by discovering an {@code @Inject} constructor).
+ */
+ boolean isValidImplicitProvisionKey(final Types types) {
+ // Qualifiers disqualify implicit provisioning.
+ if (qualifier().isPresent()) {
+ return false;
+ }
+
+ return type().accept(new SimpleTypeVisitor6<Boolean, Void>() {
+ @Override protected Boolean defaultAction(TypeMirror e, Void p) {
+ return false; // Only declared types are allowed.
+ }
+
+ @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);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(Key.class)
+ .omitNullValues()
+ .add("qualifier", qualifier().orNull())
+ .add("type", type())
+ .toString();
+ }
+
+ static final class Factory {
+ private final Types types;
+ private final Elements elements;
+
+ Factory(Types types, Elements elements) {
+ this.types = checkNotNull(types);
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ private TypeElement getMapElement() {
+ return elements.getTypeElement(Map.class.getCanonicalName());
+ }
+
+ private TypeElement getProviderElement() {
+ return elements.getTypeElement(Provider.class.getCanonicalName());
+ }
+
+ private TypeElement getProducerElement() {
+ return elements.getTypeElement(Producer.class.getCanonicalName());
+ }
+
+ private TypeElement getClassElement(Class<?> cls) {
+ return elements.getTypeElement(cls.getCanonicalName());
+ }
+
+ Key forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ TypeMirror returnType = normalize(types, componentMethod.getReturnType());
+ return forMethod(componentMethod, returnType);
+ }
+
+ Key forProductionComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ TypeMirror returnType = normalize(types, componentMethod.getReturnType());
+ TypeMirror keyType = returnType;
+ if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
+ }
+ return forMethod(componentMethod, keyType);
+ }
+
+ Key forSubcomponentBuilderMethod(
+ ExecutableElement subcomponentBuilderMethod, DeclaredType declaredContainer) {
+ checkNotNull(subcomponentBuilderMethod);
+ checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD));
+ ExecutableType resolvedMethod =
+ asExecutable(types.asMemberOf(declaredContainer, subcomponentBuilderMethod));
+ TypeMirror returnType = normalize(types, resolvedMethod.getReturnType());
+ return forMethod(subcomponentBuilderMethod, returnType);
+ }
+
+ Key forProvidesMethod(ExecutableType executableType, ExecutableElement method) {
+ checkNotNull(method);
+ checkArgument(method.getKind().equals(METHOD));
+ Provides providesAnnotation = method.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+ TypeMirror returnType = normalize(types, executableType.getReturnType());
+ TypeMirror keyType =
+ providesOrProducesKeyType(
+ returnType,
+ method,
+ Optional.of(providesAnnotation.type()),
+ Optional.<Produces.Type>absent());
+ return forMethod(method, keyType);
+ }
+
+ // TODO(user): Reconcile this method with forProvidesMethod when Provides.Type and
+ // Produces.Type are no longer different.
+ Key forProducesMethod(ExecutableType executableType, ExecutableElement method) {
+ checkNotNull(method);
+ checkArgument(method.getKind().equals(METHOD));
+ Produces producesAnnotation = method.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+ TypeMirror returnType = normalize(types, executableType.getReturnType());
+ TypeMirror unfuturedType = returnType;
+ if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ unfuturedType =
+ Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
+ }
+ TypeMirror keyType =
+ providesOrProducesKeyType(
+ unfuturedType,
+ method,
+ Optional.<Provides.Type>absent(),
+ Optional.of(producesAnnotation.type()));
+ return forMethod(method, keyType);
+ }
+
+ private TypeMirror providesOrProducesKeyType(
+ TypeMirror returnType,
+ ExecutableElement method,
+ Optional<Provides.Type> providesType,
+ Optional<Produces.Type> producesType) {
+ switch (providesType.isPresent()
+ ? providesType.get()
+ : Provides.Type.valueOf(producesType.get().name())) {
+ case UNIQUE:
+ return returnType;
+ case SET:
+ return types.getDeclaredType(getSetElement(), returnType);
+ case MAP:
+ return mapOfFactoryType(
+ method,
+ returnType,
+ providesType.isPresent() ? getProviderElement() : getProducerElement());
+ case SET_VALUES:
+ // TODO(gak): do we want to allow people to use "covariant return" here?
+ checkArgument(MoreTypes.isType(returnType) && MoreTypes.isTypeOf(Set.class, returnType));
+ return returnType;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private TypeMirror mapOfFactoryType(
+ ExecutableElement method, TypeMirror valueType, TypeElement factoryType) {
+ TypeMirror mapKeyType = mapKeyType(method);
+ TypeMirror mapValueFactoryType = types.getDeclaredType(factoryType, valueType);
+ return types.getDeclaredType(getMapElement(), mapKeyType, mapValueFactoryType);
+ }
+
+ private TypeMirror mapKeyType(ExecutableElement method) {
+ AnnotationMirror mapKeyAnnotation = getMapKey(method).get();
+ return MapKeys.unwrapValue(mapKeyAnnotation).isPresent()
+ ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
+ : mapKeyAnnotation.getAnnotationType();
+ }
+
+ private Key forMethod(ExecutableElement method, TypeMirror keyType) {
+ return new AutoValue_Key(
+ wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(method)),
+ MoreTypes.equivalence().wrap(keyType));
+ }
+
+ Key forInjectConstructorWithResolvedType(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(type));
+ }
+
+ Key forComponent(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ Key forMembersInjectedType(TypeMirror type) {
+ return new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
+ return new AutoValue_Key(
+ wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier),
+ MoreTypes.equivalence().wrap(normalize(types, type)));
+ }
+
+ /**
+ * 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>}, a key of {@code Map<K, Provider<V>>} will be returned.
+ */
+ Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
+ return maybeWrapMapValue(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>}, a key of {@code Map<K, Producer<V>>} will be returned.
+ */
+ Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
+ return maybeWrapMapValue(possibleMapKey, Producer.class);
+ }
+
+ /**
+ * Returns a key of {@link Map}{@code <K, WrappingClass<V>>} if the input key represents a
+ * {@code Map<K, V>}.
+ */
+ private Optional<Key> maybeWrapMapValue(Key possibleMapKey, Class<?> wrappingClass) {
+ if (MoreTypes.isTypeOf(Map.class, possibleMapKey.type())) {
+ DeclaredType declaredMapType = MoreTypes.asDeclared(possibleMapKey.type());
+ TypeMirror mapValueType = Util.getValueTypeOfMap(declaredMapType);
+ if (!MoreTypes.isTypeOf(wrappingClass, mapValueType)) {
+ TypeMirror keyType = Util.getKeyTypeOfMap(declaredMapType);
+ TypeElement wrappingElement = getClassElement(wrappingClass);
+ if (wrappingElement == null) {
+ // This target might not be compiled with Producers, so wrappingClass might not have an
+ // associated element.
+ return Optional.absent();
+ }
+ DeclaredType wrappedType = types.getDeclaredType(wrappingElement, mapValueType);
+ TypeMirror mapType = types.getDeclaredType(getMapElement(), keyType, wrappedType);
+ return Optional.<Key>of(new AutoValue_Key(
+ possibleMapKey.wrappedQualifier(),
+ MoreTypes.equivalence().wrap(mapType)));
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Optionally extract a {@link Key} for a {@code Set<T>} if the given key is for
+ * {@code Set<Produced<T>>}.
+ */
+ Optional<Key> implicitSetKeyFromProduced(Key possibleSetOfProducedKey) {
+ if (MoreTypes.isTypeOf(Set.class, possibleSetOfProducedKey.type())) {
+ TypeMirror argType =
+ MoreTypes.asDeclared(possibleSetOfProducedKey.type()).getTypeArguments().get(0);
+ if (MoreTypes.isTypeOf(Produced.class, argType)) {
+ TypeMirror producedArgType = MoreTypes.asDeclared(argType).getTypeArguments().get(0);
+ TypeMirror setType = types.getDeclaredType(getSetElement(), producedArgType);
+ return Optional.of(possibleSetOfProducedKey.withType(types, setType));
+ }
+ }
+ return Optional.absent();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java b/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java
new file mode 100644
index 0000000..6e695f3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/KeyFormatter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen;
+
+/**
+ * Formats a {@link Key} into a {@link String} suitable for use in error messages
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class KeyFormatter extends Formatter<Key> {
+
+ @Override public String format(Key request) {
+ StringBuilder builder = new StringBuilder();
+ if (request.qualifier().isPresent()) {
+ builder.append(request.qualifier().get());
+ builder.append(' ');
+ }
+ builder.append(request.type()); // TODO(cgruber): Use TypeMirrorFormatter.
+ return builder.toString();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java b/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java
new file mode 100644
index 0000000..5fe12b1
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/KeyVariableNamer.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Function;
+import java.util.Iterator;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+
+/**
+ * Suggests a variable name for a type based on a {@link Key}. Prefer
+ * {@link DependencyVariableNamer} for cases where a specific {@link DependencyRequest} is present.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+enum KeyVariableNamer implements Function<Key, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(Key key) {
+ 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(new SimpleTypeVisitor6<Void, StringBuilder>() {
+ @Override
+ public Void visitDeclared(DeclaredType t, StringBuilder builder) {
+ builder.append(t.asElement().getSimpleName());
+ Iterator<? extends TypeMirror> argumentIterator = t.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;
+ }
+ }, builder);
+
+ return UPPER_CAMEL.to(LOWER_CAMEL, builder.toString());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java
new file mode 100644
index 0000000..8d72e5e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyGenerator.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.auto.value.AutoAnnotation;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.MapKey;
+import dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+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;
+
+import static dagger.internal.codegen.MapKeys.getMapKeyCreatorClassName;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * Generates classes that create annotations required to instantiate {@link MapKey}s.
+ *
+ * @since 2.0
+ */
+final class MapKeyGenerator extends SourceFileGenerator<MapKeyCreatorSpecification> {
+
+ /**
+ * Specification of the {@link MapKey} annotation and the annotation type to generate.
+ */
+ @AutoValue
+ abstract static class MapKeyCreatorSpecification {
+ /**
+ * The {@link MapKey}-annotated annotation.
+ */
+ abstract TypeElement mapKeyElement();
+
+ /**
+ * The annotation type to write create methods for. For wrapped {@link MapKey}s, this is
+ * {@link #mapKeyElement()}. For unwrapped {@code MapKey}s whose single element is an
+ * annotation, this is that annotation element.
+ */
+ abstract TypeElement annotationElement();
+
+ /**
+ * Returns a specification for a wrapped {@link MapKey}-annotated annotation.
+ */
+ static MapKeyCreatorSpecification wrappedMapKey(TypeElement mapKeyElement) {
+ return new AutoValue_MapKeyGenerator_MapKeyCreatorSpecification(mapKeyElement, mapKeyElement);
+ }
+
+ /**
+ * Returns a specification for an unwrapped {@link MapKey}-annotated annotation whose single
+ * element is a nested annotation.
+ */
+ static MapKeyCreatorSpecification unwrappedMapKeyWithAnnotationValue(
+ TypeElement mapKeyElement, TypeElement annotationElement) {
+ return new AutoValue_MapKeyGenerator_MapKeyCreatorSpecification(
+ mapKeyElement, annotationElement);
+ }
+ }
+
+ MapKeyGenerator(Filer filer) {
+ super(filer);
+ }
+
+ @Override
+ ClassName nameGeneratedType(MapKeyCreatorSpecification mapKeyCreatorType) {
+ return getMapKeyCreatorClassName(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(MapKeyCreatorSpecification mapKeyCreatorType) {
+ return ImmutableSet.of(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(
+ MapKeyCreatorSpecification mapKeyCreatorType) {
+ return Optional.of(mapKeyCreatorType.mapKeyElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(
+ ClassName generatedTypeName, MapKeyCreatorSpecification mapKeyCreatorType) {
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+ TypeWriter mapKeyCreatorWriter = writer.addClass(generatedTypeName.simpleName());
+ mapKeyCreatorWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ mapKeyCreatorWriter.addModifiers(PUBLIC, FINAL);
+
+ for (TypeElement annotationElement :
+ nestedAnnotationElements(mapKeyCreatorType.annotationElement())) {
+ writeCreateMethod(mapKeyCreatorWriter, annotationElement);
+ }
+
+ return ImmutableSet.of(writer);
+ }
+
+ private void writeCreateMethod(TypeWriter mapKeyCreatorWriter, TypeElement annotationElement) {
+ MethodWriter createMethod =
+ mapKeyCreatorWriter.addMethod(
+ annotationElement.asType(), "create" + annotationElement.getSimpleName());
+
+ createMethod.annotate(AutoAnnotation.class);
+ createMethod.addModifiers(PUBLIC, STATIC);
+
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (ExecutableElement annotationMember : methodsIn(annotationElement.getEnclosedElements())) {
+ String parameterName = annotationMember.getSimpleName().toString();
+ TypeName parameterType = TypeNames.forTypeMirror(annotationMember.getReturnType());
+ createMethod.addParameter(parameterType, parameterName);
+ parameters.add(Snippet.format("%s", parameterName));
+ }
+
+ ClassName autoAnnotationClass = mapKeyCreatorWriter.name().peerNamed(
+ "AutoAnnotation_" + mapKeyCreatorWriter.name().simpleName() + "_" + createMethod.name());
+ createMethod.body().addSnippet(
+ "return new %s(%s);", autoAnnotationClass, makeParametersSnippet(parameters.build()));
+ }
+
+ private static Set<TypeElement> nestedAnnotationElements(TypeElement annotationElement) {
+ return nestedAnnotationElements(annotationElement, new LinkedHashSet<TypeElement>());
+ }
+
+ 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/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java
new file mode 100644
index 0000000..c4a264a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyProcessingStep.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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;
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import dagger.MapKey;
+import dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.util.Types;
+
+import static dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification.unwrappedMapKeyWithAnnotationValue;
+import static dagger.internal.codegen.MapKeyGenerator.MapKeyCreatorSpecification.wrappedMapKey;
+import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
+
+/**
+ * The annotation processor responsible for validating the mapKey annotation and auto-generate
+ * implementation of annotations marked with @MapKey where necessary.
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ */
+public class MapKeyProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final Types types;
+ private final MapKeyValidator mapKeyValidator;
+ private final MapKeyGenerator mapKeyGenerator;
+
+ MapKeyProcessingStep(
+ Messager messager,
+ Types types,
+ MapKeyValidator mapKeyValidator,
+ MapKeyGenerator mapKeyGenerator) {
+ this.messager = messager;
+ this.types = types;
+ this.mapKeyValidator = mapKeyValidator;
+ this.mapKeyGenerator = mapKeyGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(MapKey.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ for (Element element : elementsByAnnotation.get(MapKey.class)) {
+ ValidationReport<Element> mapKeyReport = mapKeyValidator.validate(element);
+ mapKeyReport.printMessagesTo(messager);
+
+ if (mapKeyReport.isClean()) {
+ MapKey mapkey = element.getAnnotation(MapKey.class);
+ if (mapkey.unwrapValue()) {
+ DeclaredType keyType =
+ getUnwrappedMapKeyType(MoreTypes.asDeclared(element.asType()), types);
+ if (keyType.asElement().getKind() == ElementKind.ANNOTATION_TYPE) {
+ writeCreatorClass(
+ unwrappedMapKeyWithAnnotationValue(
+ MoreElements.asType(element), MoreTypes.asTypeElement(keyType)));
+ }
+ } else {
+ writeCreatorClass(wrappedMapKey(MoreElements.asType(element)));
+ }
+ }
+ }
+ return ImmutableSet.of();
+ }
+
+ private void writeCreatorClass(MapKeyCreatorSpecification mapKeyCreatorType) {
+ try {
+ mapKeyGenerator.generate(mapKeyCreatorType);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java b/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java
new file mode 100644
index 0000000..586a1e9
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeyValidator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 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.type.TypeKind;
+
+import static dagger.internal.codegen.ErrorMessages.MAPKEY_WITHOUT_MEMBERS;
+import static dagger.internal.codegen.ErrorMessages.UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER;
+import static dagger.internal.codegen.ErrorMessages.UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * A validator for {@link MapKey} annotations.
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ */
+// TODO(dpb,gak): Should unwrapped MapKeys be required to have their single member be named "value"?
+final class MapKeyValidator {
+ ValidationReport<Element> validate(Element element) {
+ ValidationReport.Builder<Element> builder = ValidationReport.about(element);
+ List<ExecutableElement> members = methodsIn(((TypeElement) element).getEnclosedElements());
+ if (members.isEmpty()) {
+ builder.addError(MAPKEY_WITHOUT_MEMBERS, element);
+ } else if (element.getAnnotation(MapKey.class).unwrapValue()) {
+ if (members.size() > 1) {
+ builder.addError(UNWRAPPED_MAP_KEY_WITH_TOO_MANY_MEMBERS, element);
+ } else if (members.get(0).getReturnType().getKind() == TypeKind.ARRAY) {
+ builder.addError(UNWRAPPED_MAP_KEY_WITH_ARRAY_MEMBER, element);
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MapKeys.java b/compiler/src/main/java/dagger/internal/codegen/MapKeys.java
new file mode 100644
index 0000000..fbbd8cf
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MapKeys.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.MapKey;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+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.element.VariableElement;
+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.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+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.google.common.collect.Iterables.transform;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+/**
+ * Methods for extracting {@link MapKey} annotations and key snippets 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<? extends AnnotationMirror> getMapKey(Element bindingElement) {
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(bindingElement);
+ return mapKeys.isEmpty()
+ ? Optional.<AnnotationMirror>absent()
+ : Optional.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(mapKey.getElementValues().values()))
+ : Optional.<AnnotationValue>absent();
+ }
+
+ /**
+ * 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 Types 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 the name of the generated class that contains the static {@code create} methods for a
+ * {@link MapKey} annotation type.
+ */
+ public static ClassName getMapKeyCreatorClassName(TypeElement mapKeyType) {
+ ClassName mapKeyTypeName = ClassName.fromTypeElement(mapKeyType);
+ return mapKeyTypeName.topLevelClassName().peerNamed(mapKeyTypeName.classFileName() + "Creator");
+ }
+
+ /**
+ * Returns a snippet for the map key specified by the {@link MapKey} annotation on
+ * {@code bindingElement}.
+ *
+ * @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
+ */
+ static Snippet getMapKeySnippet(Element bindingElement) {
+ AnnotationMirror mapKey = getMapKey(bindingElement).get();
+ ClassName mapKeyCreator =
+ getMapKeyCreatorClassName(MoreTypes.asTypeElement(mapKey.getAnnotationType()));
+ Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
+ if (unwrappedValue.isPresent()) {
+ return new MapKeySnippetExceptArrays(mapKeyCreator)
+ .visit(unwrappedValue.get(), unwrappedValue.get());
+ } else {
+ return annotationSnippet(mapKey, new MapKeySnippet(mapKeyCreator));
+ }
+ }
+
+ /**
+ * Returns a snippet to create the visited value in code. Expects its parameter to be a class with
+ * static creation methods for all nested annotation types.
+ *
+ * <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}</code>, but in code it would have to be <code> new int[] {1, 2, 3}</code>.
+ */
+ private static class MapKeySnippet
+ extends SimpleAnnotationValueVisitor6<Snippet, AnnotationValue> {
+
+ final ClassName mapKeyCreator;
+
+ MapKeySnippet(ClassName mapKeyCreator) {
+ this.mapKeyCreator = mapKeyCreator;
+ }
+
+ @Override
+ public Snippet visitEnumConstant(VariableElement c, AnnotationValue p) {
+ return Snippet.format(
+ "%s.%s", TypeNames.forTypeMirror(c.getEnclosingElement().asType()), c.getSimpleName());
+ }
+
+ @Override
+ public Snippet visitAnnotation(AnnotationMirror a, AnnotationValue p) {
+ return annotationSnippet(a, this);
+ }
+
+ @Override
+ public Snippet visitType(TypeMirror t, AnnotationValue p) {
+ return Snippet.format("%s.class", TypeNames.forTypeMirror(t));
+ }
+
+ @Override
+ public Snippet visitString(String s, AnnotationValue p) {
+ return Snippet.format("%s", p);
+ }
+
+ @Override
+ public Snippet visitByte(byte b, AnnotationValue p) {
+ return Snippet.format("(byte) %s", b);
+ }
+
+ @Override
+ public Snippet visitChar(char c, AnnotationValue p) {
+ return Snippet.format("%s", p);
+ }
+
+ @Override
+ public Snippet visitDouble(double d, AnnotationValue p) {
+ return Snippet.format("%sD", d);
+ }
+
+ @Override
+ public Snippet visitFloat(float f, AnnotationValue p) {
+ return Snippet.format("%sF", f);
+ }
+
+ @Override
+ public Snippet visitInt(int i, AnnotationValue p) {
+ return Snippet.format("(int) %s", i);
+ }
+
+ @Override
+ public Snippet visitLong(long i, AnnotationValue p) {
+ return Snippet.format("%sL", i);
+ }
+
+ @Override
+ public Snippet visitShort(short s, AnnotationValue p) {
+ return Snippet.format("(short) %s", s);
+ }
+
+ @Override
+ protected Snippet defaultAction(Object o, AnnotationValue p) {
+ return Snippet.format("%s", o);
+ }
+
+ @Override
+ public Snippet visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ for (int i = 0; i < values.size(); i++) {
+ snippets.add(this.visit(values.get(i), p));
+ }
+ return Snippet.format("{%s}", makeParametersSnippet(snippets.build()));
+ }
+ }
+
+ /**
+ * Returns a snippet for the visited value. Expects its parameter to be a class with static
+ * creation methods for all nested annotation types.
+ *
+ * <p>Throws {@link IllegalArgumentException} if the visited value is an array.
+ */
+ private static class MapKeySnippetExceptArrays extends MapKeySnippet {
+
+ MapKeySnippetExceptArrays(ClassName mapKeyCreator) {
+ super(mapKeyCreator);
+ }
+
+ @Override
+ public Snippet visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
+ throw new IllegalArgumentException("Cannot unwrap arrays");
+ }
+ }
+
+ /**
+ * Returns a snippet that calls a static method on {@code mapKeySnippet.mapKeyCreator} to create
+ * an annotation from {@code mapKeyAnnotation}.
+ */
+ private static Snippet annotationSnippet(
+ AnnotationMirror mapKeyAnnotation, final MapKeySnippet mapKeySnippet) {
+ return Snippet.format(
+ "%s.create%s(%s)",
+ mapKeySnippet.mapKeyCreator,
+ mapKeyAnnotation.getAnnotationType().asElement().getSimpleName(),
+ makeParametersSnippet(
+ transform(
+ getAnnotationValuesWithDefaults(mapKeyAnnotation).entrySet(),
+ new Function<Map.Entry<ExecutableElement, AnnotationValue>, Snippet>() {
+ @Override
+ public Snippet apply(Map.Entry<ExecutableElement, AnnotationValue> entry) {
+ return ARRAY_LITERAL_PREFIX.visit(
+ entry.getKey().getReturnType(),
+ mapKeySnippet.visit(entry.getValue(), entry.getValue()));
+ }
+ })));
+ }
+
+ /**
+ * If the visited type is an array, prefixes the parameter snippet with {@code new T[]}, where
+ * {@code T} is the raw array component type.
+ */
+ private static final SimpleTypeVisitor6<Snippet, Snippet> ARRAY_LITERAL_PREFIX =
+ new SimpleTypeVisitor6<Snippet, Snippet>() {
+
+ @Override
+ public Snippet visitArray(ArrayType t, Snippet p) {
+ return Snippet.format("new %s[] %s", RAW_TYPE_NAME.visit(t.getComponentType()), p);
+ }
+
+ @Override
+ protected Snippet defaultAction(TypeMirror e, Snippet 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.fromTypeElement(MoreTypes.asTypeElement(t));
+ }
+
+ @Override
+ protected TypeName defaultAction(TypeMirror e, Void p) {
+ return TypeNames.forTypeMirror(e);
+ }
+ };
+
+ private MapKeys() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java b/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java
new file mode 100644
index 0000000..7fbcf11
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MembersInjectionBinding.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.SetMultimap;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+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.ElementKindVisitor6;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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 javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Represents the full members injection of a particular type. This does not pay attention to
+ * injected members on supertypes.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class MembersInjectionBinding extends Binding {
+ @Override abstract TypeElement bindingElement();
+
+ /** The set of individual sites where {@link Inject} is applied. */
+ abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+ abstract Optional<DependencyRequest> parentInjectorRequest();
+
+ enum Strategy {
+ NO_OP,
+ INJECT_MEMBERS,
+ }
+
+ Strategy injectionStrategy() {
+ return injectionSites().isEmpty() ? Strategy.NO_OP : Strategy.INJECT_MEMBERS;
+ }
+
+ MembersInjectionBinding withoutParentInjectorRequest() {
+ return new AutoValue_MembersInjectionBinding(
+ key(),
+ dependencies(),
+ implicitDependencies(),
+ bindingPackage(),
+ hasNonDefaultTypeParameters(),
+ bindingElement(),
+ injectionSites(),
+ Optional.<DependencyRequest>absent());
+ }
+
+ @Override
+ protected Binding.Type bindingType() {
+ return Binding.Type.MEMBERS_INJECTION;
+ }
+
+ @AutoValue
+ abstract static class InjectionSite {
+ enum Kind {
+ FIELD,
+ METHOD,
+ }
+
+ abstract Kind kind();
+
+ abstract Element element();
+
+ abstract ImmutableSet<DependencyRequest> dependencies();
+
+ protected int indexAmongSiblingMembers(InjectionSite injectionSite) {
+ return injectionSite
+ .element()
+ .getEnclosingElement()
+ .getEnclosedElements()
+ .indexOf(injectionSite.element());
+ }
+ }
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(Elements elements, Types types, Key.Factory keyFactory,
+ DependencyRequest.Factory dependencyRequestFactory) {
+ this.elements = checkNotNull(elements);
+ this.types = checkNotNull(types);
+ this.keyFactory = checkNotNull(keyFactory);
+ this.dependencyRequestFactory = checkNotNull(dependencyRequestFactory);
+ }
+
+ private InjectionSite injectionSiteForInjectMethod(
+ ExecutableElement methodElement, DeclaredType containingType) {
+ checkNotNull(methodElement);
+ checkArgument(methodElement.getKind().equals(ElementKind.METHOD));
+ ExecutableType resolved =
+ MoreTypes.asExecutable(types.asMemberOf(containingType, methodElement));
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ InjectionSite.Kind.METHOD,
+ methodElement,
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ containingType, methodElement.getParameters(), resolved.getParameterTypes()));
+ }
+
+ private InjectionSite injectionSiteForInjectField(
+ VariableElement fieldElement, DeclaredType containingType) {
+ checkNotNull(fieldElement);
+ checkArgument(fieldElement.getKind().equals(ElementKind.FIELD));
+ checkArgument(isAnnotationPresent(fieldElement, Inject.class));
+ TypeMirror resolved = types.asMemberOf(containingType, fieldElement);
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ InjectionSite.Kind.FIELD,
+ fieldElement,
+ ImmutableSet.of(
+ dependencyRequestFactory.forRequiredResolvedVariable(
+ containingType, fieldElement, resolved)));
+ }
+
+ /** Returns an unresolved version of this binding. */
+ MembersInjectionBinding unresolve(MembersInjectionBinding binding) {
+ checkState(binding.hasNonDefaultTypeParameters());
+ DeclaredType unresolved = MoreTypes.asDeclared(binding.bindingElement().asType());
+ return forInjectedType(unresolved, Optional.<TypeMirror>absent());
+ }
+
+ /** Returns true if the type has some injected members in itself or any of its super classes. */
+ boolean hasInjectedMembers(DeclaredType declaredType) {
+ return !getInjectionSites(declaredType).isEmpty();
+ }
+
+ /**
+ * Returns a MembersInjectionBinding for the given type. If {@code resolvedType} is present,
+ * this will return a resolved binding, with the key & type resolved to the given type (using
+ * {@link Types#asMemberOf(DeclaredType, Element)}).
+ */
+ MembersInjectionBinding forInjectedType(
+ 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 = MoreTypes.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 = getInjectionSites(declaredType);
+ ImmutableSet<DependencyRequest> dependencies =
+ FluentIterable.from(injectionSites)
+ .transformAndConcat(
+ new Function<InjectionSite, Set<DependencyRequest>>() {
+ @Override
+ public Set<DependencyRequest> apply(InjectionSite input) {
+ return input.dependencies();
+ }
+ })
+ .toSet();
+
+ Optional<DependencyRequest> parentInjectorRequest =
+ MoreTypes.nonObjectSuperclass(types, elements, declaredType)
+ .transform(
+ new Function<DeclaredType, DependencyRequest>() {
+ @Override
+ public DependencyRequest apply(DeclaredType input) {
+ return dependencyRequestFactory.forMembersInjectedType(input);
+ }
+ });
+
+ Key key = keyFactory.forMembersInjectedType(declaredType);
+ TypeElement typeElement = MoreElements.asType(declaredType.asElement());
+ return new AutoValue_MembersInjectionBinding(
+ key,
+ dependencies,
+ dependencies,
+ findBindingPackage(key),
+ hasNonDefaultTypeParameters(typeElement, key.type(), types),
+ typeElement,
+ injectionSites,
+ parentInjectorRequest);
+ }
+
+ private ImmutableSortedSet<InjectionSite> getInjectionSites(DeclaredType declaredType) {
+ Set<InjectionSite> injectionSites = new HashSet<>();
+ final List<TypeElement> ancestors = new ArrayList<>();
+ SetMultimap<String, ExecutableElement> overriddenMethodMap = LinkedHashMultimap.create();
+ for (Optional<DeclaredType> currentType = Optional.of(declaredType);
+ currentType.isPresent();
+ currentType = MoreTypes.nonObjectSuperclass(types, elements, currentType.get())) {
+ final 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() == InjectionSite.Kind.METHOD) {
+ ExecutableElement injectionSiteMethod =
+ MoreElements.asExecutable(injectionSite.element());
+ overriddenMethodMap.put(
+ injectionSiteMethod.getSimpleName().toString(), injectionSiteMethod);
+ }
+ }
+ }
+ }
+ return ImmutableSortedSet.copyOf(
+ new Comparator<InjectionSite>() {
+ @Override
+ public int compare(InjectionSite left, InjectionSite right) {
+ return ComparisonChain.start()
+ // supertypes before subtypes
+ .compare(
+ ancestors.indexOf(right.element().getEnclosingElement()),
+ ancestors.indexOf(left.element().getEnclosingElement()))
+ // fields before methods
+ .compare(left.element().getKind(), right.element().getKind())
+ // then sort by whichever element comes first in the parent
+ // this isn't necessary, but makes the processor nice and predictable
+ .compare(
+ left.indexAmongSiblingMembers(left), right.indexAmongSiblingMembers(right))
+ .result();
+ }
+ },
+ 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;
+ }
+
+ private final ElementVisitor<Optional<InjectionSite>, DeclaredType> injectionSiteVisitor =
+ new ElementKindVisitor6<Optional<InjectionSite>, DeclaredType>(
+ Optional.<InjectionSite>absent()) {
+ @Override
+ public Optional<InjectionSite> visitExecutableAsMethod(
+ ExecutableElement e, DeclaredType type) {
+ return Optional.of(injectionSiteForInjectMethod(e, type));
+ }
+
+ @Override
+ public Optional<InjectionSite> visitVariableAsField(
+ VariableElement e, DeclaredType type) {
+ return (isAnnotationPresent(e, Inject.class)
+ && !e.getModifiers().contains(PRIVATE)
+ && !e.getModifiers().contains(STATIC))
+ ? Optional.of(injectionSiteForInjectField(e, type))
+ : Optional.<InjectionSite>absent();
+ }
+ };
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java b/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java
new file mode 100644
index 0000000..3694d2e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MembersInjectorGenerator.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.CaseFormat;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+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.Lists;
+import dagger.MembersInjector;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Modifiable;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.internal.codegen.writer.TypeVariableName;
+import dagger.internal.codegen.writer.VariableWriter;
+import dagger.internal.codegen.writer.VoidName;
+import dagger.producers.Producer;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor7;
+
+import static com.google.auto.common.MoreElements.getPackage;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link MembersInjector} implementations from {@link MembersInjectionBinding} instances.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class MembersInjectorGenerator extends SourceFileGenerator<MembersInjectionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+
+ MembersInjectorGenerator(
+ Filer filer,
+ DependencyRequestMapper dependencyRequestMapper) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ }
+
+ @Override
+ ClassName nameGeneratedType(MembersInjectionBinding binding) {
+ return membersInjectorNameForType(binding.bindingElement());
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(
+ MembersInjectionBinding binding) {
+ return FluentIterable.from(binding.injectionSites())
+ .transform(new Function<InjectionSite, Element>() {
+ @Override public Element apply(InjectionSite injectionSite) {
+ return injectionSite.element();
+ }
+ })
+ .toSet();
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(MembersInjectionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, MembersInjectionBinding binding) {
+ // Empty members injection bindings are special and don't need source files.
+ if (binding.injectionSites().isEmpty()) {
+ return ImmutableSet.of();
+ }
+ Set<String> delegateMethods = new HashSet<>();
+
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkState(!binding.hasNonDefaultTypeParameters());
+
+ TypeName injectedTypeName = TypeNames.forTypeMirror(binding.key().type());
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ ClassWriter injectorWriter = writer.addClass(generatedTypeName.simpleName());
+ List<TypeVariableName> typeParameters = Lists.newArrayList();
+ for (TypeParameterElement typeParameter : binding.bindingTypeElement().getTypeParameters()) {
+ typeParameters.add(TypeVariableName.fromTypeParameterElement(typeParameter));
+ }
+ injectorWriter.addTypeParameters(typeParameters);
+ injectorWriter.annotate(Generated.class)
+ .setValue(ComponentProcessor.class.getCanonicalName());
+ injectorWriter.addModifiers(PUBLIC, FINAL);
+ TypeName implementedType =
+ ParameterizedTypeName.create(MembersInjector.class, injectedTypeName);
+ injectorWriter.addImplementedType(implementedType);
+
+ ConstructorWriter constructorWriter = injectorWriter.addConstructor();
+ constructorWriter.addModifiers(PUBLIC);
+ MethodWriter injectMembersWriter = injectorWriter.addMethod(VoidName.VOID, "injectMembers");
+ injectMembersWriter.addModifiers(PUBLIC);
+ injectMembersWriter.annotate(Override.class);
+ injectMembersWriter.addParameter(injectedTypeName, "instance");
+ injectMembersWriter.body().addSnippet(Joiner.on('\n').join(
+ "if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ "}"));
+
+ ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, ImmutableSet.copyOf(binding.dependencies()));
+
+ ImmutableMap.Builder<BindingKey, FieldWriter> dependencyFieldsBuilder =
+ ImmutableMap.builder();
+
+ // 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.)
+ MethodWriter createMethodWriter = injectorWriter.addMethod(implementedType, "create");
+ createMethodWriter.addTypeParameters(typeParameters);
+ createMethodWriter.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
+
+ boolean usesRawFrameworkTypes = false;
+ for (Entry<BindingKey, FrameworkField> fieldEntry : fields.entrySet()) {
+ BindingKey bindingKey = 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 =
+ !VISIBLE_TO_MEMBERS_INJECTOR.visit(bindingKey.key().type(), binding);
+
+ FieldWriter field =
+ injectorWriter.addField(
+ useRawFrameworkType
+ ? bindingField.frameworkType().type()
+ : bindingField.frameworkType(),
+ bindingField.name());
+
+ field.addModifiers(PRIVATE, FINAL);
+ VariableWriter constructorParameter =
+ constructorWriter.addParameter(field.type(), field.name());
+ VariableWriter createMethodParameter =
+ createMethodWriter.addParameter(constructorParameter.type(), constructorParameter.name());
+
+ // 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;
+ suppressRawTypesWarning(field);
+ suppressRawTypesWarning(constructorParameter);
+ suppressRawTypesWarning(createMethodParameter);
+ }
+
+ constructorWriter.body().addSnippet("assert %s != null;", field.name());
+ constructorWriter.body().addSnippet("this.%1$s = %1$s;", field.name());
+ dependencyFieldsBuilder.put(bindingKey, field);
+ }
+
+ createMethodWriter
+ .body()
+ .addSnippet(
+ " return new %s(%s);",
+ parameterizedGeneratedTypeNameForBinding(binding),
+ Joiner.on(", ").join(constructorWriter.parameters().keySet()));
+
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields = dependencyFieldsBuilder.build();
+ for (InjectionSite injectionSite : binding.injectionSites()) {
+ injectMembersWriter
+ .body()
+ .addSnippet(
+ visibleToMembersInjector(binding, injectionSite.element())
+ ? directInjectMemberSnippet(binding, dependencyFields, injectionSite)
+ : delegateInjectMemberSnippet(dependencyFields, injectionSite));
+ if (!injectionSite.element().getModifiers().contains(PUBLIC)
+ && injectionSite.element().getEnclosingElement().equals(binding.bindingElement())
+ && delegateMethods.add(injectionSiteDelegateMethodName(injectionSite.element()))) {
+ writeInjectorMethodForSubclasses(
+ injectorWriter,
+ dependencyFields,
+ typeParameters,
+ injectedTypeName,
+ injectionSite.element(),
+ injectionSite.dependencies());
+ }
+ }
+
+ if (usesRawFrameworkTypes) {
+ injectMembersWriter.annotate(SuppressWarnings.class).setValue("unchecked");
+ }
+
+ return ImmutableSet.of(writer);
+ }
+
+ /**
+ * Returns {@code true} if {@code element} is visible to the members injector for {@code binding}.
+ */
+ // TODO(dpb,gak): Make sure that all cases are covered here. E.g., what if element is public but
+ // enclosed in a package-private element?
+ private static boolean visibleToMembersInjector(
+ MembersInjectionBinding binding, Element element) {
+ return getPackage(element).equals(getPackage(binding.bindingElement()))
+ || element.getModifiers().contains(PUBLIC);
+ }
+
+ /**
+ * Returns a snippet that directly injects the instance's field or method.
+ */
+ private Snippet directInjectMemberSnippet(
+ MembersInjectionBinding binding,
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ InjectionSite injectionSite) {
+ return Snippet.format(
+ injectionSite.element().getKind().isField() ? "%s.%s = %s;" : "%s.%s(%s);",
+ getInstanceSnippetWithPotentialCast(
+ injectionSite.element().getEnclosingElement(), binding.bindingElement()),
+ injectionSite.element().getSimpleName(),
+ makeParametersSnippet(
+ parameterSnippets(dependencyFields, injectionSite.dependencies(), true)));
+ }
+
+ /**
+ * Returns a snippet that injects the instance's field or method by calling a static method on the
+ * parent members injector class.
+ */
+ private Snippet delegateInjectMemberSnippet(
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields, InjectionSite injectionSite) {
+ return Snippet.format(
+ "%s.%s(%s);",
+ membersInjectorNameForType(
+ MoreElements.asType(injectionSite.element().getEnclosingElement())),
+ injectionSiteDelegateMethodName(injectionSite.element()),
+ makeParametersSnippet(
+ new ImmutableList.Builder<Snippet>()
+ .add(Snippet.format("instance"))
+ .addAll(parameterSnippets(dependencyFields, injectionSite.dependencies(), false))
+ .build()));
+ }
+
+ /**
+ * Returns the parameters for injecting a member.
+ *
+ * @param passValue if {@code true}, each parameter snippet will be the result of converting the
+ * field from the framework type ({@link Provider}, {@link Producer}, etc.) to the real value;
+ * if {@code false}, each parameter snippet will be just the field
+ */
+ private ImmutableList<Snippet> parameterSnippets(
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ ImmutableSet<DependencyRequest> dependencies,
+ boolean passValue) {
+ ImmutableList.Builder<Snippet> parameters = ImmutableList.builder();
+ for (DependencyRequest dependency : dependencies) {
+ Snippet fieldSnippet =
+ Snippet.format("%s", dependencyFields.get(dependency.bindingKey()).name());
+ parameters.add(
+ passValue ? frameworkTypeUsageStatement(fieldSnippet, dependency.kind()) : fieldSnippet);
+ }
+ return parameters.build();
+ }
+
+ private Snippet getInstanceSnippetWithPotentialCast(
+ Element injectionSiteElement, Element bindingElement) {
+ return (injectionSiteElement.equals(bindingElement))
+ ? Snippet.format("instance")
+ : Snippet.format("((%s)instance)", injectionSiteElement);
+ }
+
+ private String injectionSiteDelegateMethodName(Element injectionSiteElement) {
+ return "inject"
+ + CaseFormat.LOWER_CAMEL.to(
+ CaseFormat.UPPER_CAMEL, injectionSiteElement.getSimpleName().toString());
+ }
+
+ private void writeInjectorMethodForSubclasses(
+ ClassWriter injectorWriter,
+ ImmutableMap<BindingKey, FieldWriter> dependencyFields,
+ List<TypeVariableName> typeParameters,
+ TypeName injectedTypeName,
+ Element injectionElement,
+ ImmutableSet<DependencyRequest> dependencies) {
+ MethodWriter methodWriter =
+ injectorWriter.addMethod(VoidName.VOID, injectionSiteDelegateMethodName(injectionElement));
+ methodWriter.addModifiers(PUBLIC, STATIC);
+ methodWriter.addParameter(injectedTypeName, "instance");
+ methodWriter.addTypeParameters(typeParameters);
+ ImmutableList.Builder<Snippet> providedParameters = ImmutableList.builder();
+ Set<String> parameterNames = new HashSet<>();
+ for (DependencyRequest dependency : dependencies) {
+ FieldWriter field = dependencyFields.get(dependency.bindingKey());
+ VariableWriter parameter =
+ methodWriter.addParameter(
+ field.type(),
+ staticInjectMethodDependencyParameterName(parameterNames, dependency, field));
+ providedParameters.add(
+ frameworkTypeUsageStatement(Snippet.format("%s", parameter.name()), dependency.kind()));
+ }
+ if (injectionElement.getKind().isField()) {
+ methodWriter
+ .body()
+ .addSnippet(
+ "instance.%s = %s;",
+ injectionElement.getSimpleName(),
+ getOnlyElement(providedParameters.build()));
+ } else {
+ methodWriter
+ .body()
+ .addSnippet(
+ "instance.%s(%s);",
+ injectionElement.getSimpleName(),
+ makeParametersSnippet(providedParameters.build()));
+ }
+ }
+
+ /**
+ * Returns the static inject method parameter name for a dependency.
+ *
+ * @param parameterNames the parameter names used so far
+ * @param dependency the dependency
+ * @param field the field used to hold the framework type for the dependency
+ */
+ private String staticInjectMethodDependencyParameterName(
+ Set<String> parameterNames, DependencyRequest dependency, FieldWriter field) {
+ StringBuilder parameterName =
+ new StringBuilder(dependency.requestElement().getSimpleName().toString());
+ switch (dependency.kind()) {
+ case LAZY:
+ case INSTANCE:
+ case FUTURE:
+ String suffix = ((ParameterizedTypeName) field.type()).type().simpleName();
+ if (parameterName.length() <= suffix.length()
+ || !parameterName.substring(parameterName.length() - suffix.length()).equals(suffix)) {
+ parameterName.append(suffix);
+ }
+ break;
+
+ default:
+ break;
+ }
+ int baseLength = parameterName.length();
+ for (int i = 2; !parameterNames.add(parameterName.toString()); i++) {
+ parameterName.replace(baseLength, parameterName.length(), String.valueOf(i));
+ }
+ return parameterName.toString();
+ }
+
+ private void suppressRawTypesWarning(Modifiable modifiable) {
+ modifiable.annotate(SuppressWarnings.class).setValue("rawtypes");
+ }
+
+ private static final TypeVisitor<Boolean, MembersInjectionBinding> VISIBLE_TO_MEMBERS_INJECTOR =
+ new SimpleTypeVisitor7<Boolean, MembersInjectionBinding>(true) {
+ @Override
+ public Boolean visitArray(ArrayType t, MembersInjectionBinding p) {
+ return visit(t.getComponentType(), p);
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, MembersInjectionBinding p) {
+ return visibleToMembersInjector(p, t.asElement());
+ }
+ };
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java
new file mode 100644
index 0000000..447ed24
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java
@@ -0,0 +1,33 @@
+package dagger.internal.codegen;
+
+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 javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@AutoValue
+abstract class MethodSignature {
+ abstract String name();
+ abstract ImmutableList<Equivalence.Wrapper<TypeMirror>> parameterTypes();
+ abstract ImmutableList<Equivalence.Wrapper<TypeMirror>> thrownTypes();
+
+ static MethodSignature fromExecutableType(String methodName, ExecutableType methodType) {
+ checkNotNull(methodType);
+ ImmutableList.Builder<Equivalence.Wrapper<TypeMirror>> parameters = ImmutableList.builder();
+ ImmutableList.Builder<Equivalence.Wrapper<TypeMirror>> thrownTypes = ImmutableList.builder();
+ for (TypeMirror parameter : methodType.getParameterTypes()) {
+ parameters.add(MoreTypes.equivalence().wrap(parameter));
+ }
+ for (TypeMirror thrownType : methodType.getThrownTypes()) {
+ thrownTypes.add(MoreTypes.equivalence().wrap(thrownType));
+ }
+ return new AutoValue_MethodSignature(
+ methodName,
+ parameters.build(),
+ thrownTypes.build());
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java b/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java
new file mode 100644
index 0000000..078977e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MethodSignatureFormatter.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.base.Optional;
+import java.util.Iterator;
+import java.util.List;
+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.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+
+/**
+ * Formats the signature of an {@link ExecutableElement} suitable for use in error messages.
+ *
+ * @author Christian Gruber
+ * @since 2.0
+ */
+final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
+ private final Types types;
+
+ MethodSignatureFormatter(Types types) {
+ this.types = types;
+ }
+
+ @Override public String format(ExecutableElement method) {
+ return format(method, Optional.<DeclaredType>absent());
+ }
+
+ /**
+ * Formats an ExecutableElement as if it were contained within the container, if the container is
+ * present.
+ */
+ public String format(ExecutableElement method, Optional<DeclaredType> container) {
+ StringBuilder builder = new StringBuilder();
+ 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());
+ }
+
+ // 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(ErrorMessages.format(annotationIterator.next()));
+ }
+ builder.append(' ');
+ }
+ builder.append(nameOfType(executableType.getReturnType()));
+ builder.append(' ');
+ builder.append(type.getQualifiedName());
+ builder.append('.');
+ builder.append(method.getSimpleName());
+ builder.append('(');
+ checkState(method.getParameters().size() == executableType.getParameterTypes().size());
+ Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
+ Iterator<? extends TypeMirror> parameterTypes = executableType.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) {
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(parameter);
+ if (qualifier.isPresent()) {
+ builder.append(ErrorMessages.format(qualifier.get())).append(' ');
+ }
+ builder.append(nameOfType(type));
+ }
+
+ private static String nameOfType(TypeMirror type) {
+ if (type.getKind().isPrimitive()) {
+ return MoreTypes.asPrimitiveType(type).toString();
+ } else if (type.getKind() == TypeKind.VOID) {
+ return "void";
+ } else {
+ return stripCommonTypePrefixes(MoreTypes.asDeclared(type).toString());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java b/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java
new file mode 100644
index 0000000..4b6f0c3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MissingBindingSuggestions.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * Utility code that looks for bindings matching a key in all subcomponents in a binding graph so
+ * that a user is advised that a binding exists elsewhere when it is not found in the current
+ * subgraph. If a binding matching a key exists in a sub- or sibling component, that is often what
+ * the user actually wants to use.
+ */
+class MissingBindingSuggestions {
+ /**
+ * Searches the entire binding graph from the top-level graph for a binding matching
+ * {@code key}.
+ */
+ static ImmutableList<String> forKey(BindingGraph topLevelGraph, BindingKey key) {
+ ImmutableList.Builder<String> resolutions = new ImmutableList.Builder<>();
+ Deque<BindingGraph> graphsToTry = new ArrayDeque<>();
+
+ graphsToTry.add(topLevelGraph);
+ do {
+ BindingGraph graph = graphsToTry.removeLast();
+ ResolvedBindings bindings = graph.resolvedBindings().get(key);
+ if ((bindings == null) || bindings.bindings().isEmpty()) {
+ graphsToTry.addAll(graph.subgraphs().values());
+ } else {
+ resolutions.add("A binding with matching key exists in component: "
+ + graph.componentDescriptor().componentDefinitionType().getQualifiedName());
+ }
+ } while (!graphsToTry.isEmpty());
+
+ return resolutions.build();
+ }
+
+ private MissingBindingSuggestions() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java
new file mode 100644
index 0000000..c938af2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleDescriptor.java
@@ -0,0 +1,122 @@
+package dagger.internal.codegen;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.ConfigurationAnnotations.getModuleIncludes;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.NONE;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+@AutoValue
+abstract class ModuleDescriptor {
+ static final Function<ModuleDescriptor, TypeElement> getModuleElement() {
+ return new Function<ModuleDescriptor, TypeElement>() {
+ @Override public TypeElement apply(ModuleDescriptor input) {
+ return input.moduleElement();
+ }
+ };
+ }
+
+ abstract AnnotationMirror moduleAnnotation();
+
+ abstract TypeElement moduleElement();
+
+ abstract ImmutableSet<ModuleDescriptor> includedModules();
+
+ abstract ImmutableSet<ContributionBinding> bindings();
+
+ enum DefaultCreationStrategy {
+ PASSED,
+ CONSTRUCTED,
+ }
+
+ abstract DefaultCreationStrategy defaultCreationStrategy();
+
+ static final class Factory {
+ private final Elements elements;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final ProductionBinding.Factory productionBindingFactory;
+
+ Factory(
+ Elements elements,
+ ProvisionBinding.Factory provisionBindingFactory,
+ ProductionBinding.Factory productionBindingFactory) {
+ this.elements = elements;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.productionBindingFactory = productionBindingFactory;
+ }
+
+ ModuleDescriptor create(TypeElement moduleElement) {
+ AnnotationMirror moduleAnnotation = getModuleAnnotation(moduleElement).get();
+
+ ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
+ for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
+ if (isAnnotationPresent(moduleMethod, Provides.class)) {
+ bindings.add(
+ provisionBindingFactory.forProvidesMethod(moduleMethod, moduleElement.asType()));
+ }
+ if (isAnnotationPresent(moduleMethod, Produces.class)) {
+ bindings.add(
+ productionBindingFactory.forProducesMethod(moduleMethod, moduleElement.asType()));
+ }
+ }
+
+ DefaultCreationStrategy defaultCreationStrategy =
+ (componentCanMakeNewInstances(moduleElement)
+ && moduleElement.getTypeParameters().isEmpty())
+ ? ModuleDescriptor.DefaultCreationStrategy.CONSTRUCTED
+ : ModuleDescriptor.DefaultCreationStrategy.PASSED;
+
+ return new AutoValue_ModuleDescriptor(
+ moduleAnnotation,
+ moduleElement,
+ ImmutableSet.copyOf(
+ collectIncludedModules(new LinkedHashSet<ModuleDescriptor>(), moduleElement)),
+ bindings.build(),
+ defaultCreationStrategy);
+ }
+
+ private static Optional<AnnotationMirror> getModuleAnnotation(TypeElement moduleElement) {
+ return getAnnotationMirror(moduleElement, Module.class)
+ .or(getAnnotationMirror(moduleElement, ProducerModule.class));
+ }
+
+ private Set<ModuleDescriptor> collectIncludedModules(
+ Set<ModuleDescriptor> 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);
+ }
+ }
+ Optional<AnnotationMirror> moduleAnnotation = getModuleAnnotation(moduleElement);
+ if (moduleAnnotation.isPresent()) {
+ for (TypeMirror moduleIncludesType : getModuleIncludes(moduleAnnotation.get())) {
+ includedModules.add(create(MoreTypes.asTypeElement(moduleIncludesType)));
+ }
+ }
+ return includedModules;
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java
new file mode 100644
index 0000000..1afda7d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleProcessingStep.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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;
+import com.google.auto.common.MoreElements;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.Module;
+import dagger.Provides;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the {@link Module}
+ * (and {@link Provides}) annotation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ModuleProcessingStep implements BasicAnnotationProcessor.ProcessingStep {
+ private final Messager messager;
+ private final ModuleValidator moduleValidator;
+ private final ProvidesMethodValidator providesMethodValidator;
+ private final ProvisionBinding.Factory provisionBindingFactory;
+ private final FactoryGenerator factoryGenerator;
+ private final Set<Element> processedModuleElements = Sets.newLinkedHashSet();
+
+ ModuleProcessingStep(
+ Messager messager,
+ ModuleValidator moduleValidator,
+ ProvidesMethodValidator providesMethodValidator,
+ ProvisionBinding.Factory provisionBindingFactory,
+ FactoryGenerator factoryGenerator) {
+ this.messager = messager;
+ this.moduleValidator = moduleValidator;
+ this.providesMethodValidator = providesMethodValidator;
+ this.provisionBindingFactory = provisionBindingFactory;
+ this.factoryGenerator = factoryGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(Module.class, Provides.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ // first, check and collect all provides methods
+ ImmutableSet.Builder<ExecutableElement> validProvidesMethodsBuilder = ImmutableSet.builder();
+ for (Element providesElement : elementsByAnnotation.get(Provides.class)) {
+ if (providesElement.getKind().equals(METHOD)) {
+ ExecutableElement providesMethodElement = (ExecutableElement) providesElement;
+ ValidationReport<ExecutableElement> methodReport =
+ providesMethodValidator.validate(providesMethodElement);
+ methodReport.printMessagesTo(messager);
+ if (methodReport.isClean()) {
+ validProvidesMethodsBuilder.add(providesMethodElement);
+ }
+ }
+ }
+ ImmutableSet<ExecutableElement> validProvidesMethods = validProvidesMethodsBuilder.build();
+
+ // process each module
+ for (Element moduleElement :
+ Sets.difference(elementsByAnnotation.get(Module.class), processedModuleElements)) {
+ ValidationReport<TypeElement> report =
+ moduleValidator.validate(MoreElements.asType(moduleElement));
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ ImmutableSet.Builder<ExecutableElement> moduleProvidesMethodsBuilder =
+ ImmutableSet.builder();
+ List<ExecutableElement> moduleMethods =
+ ElementFilter.methodsIn(moduleElement.getEnclosedElements());
+ for (ExecutableElement methodElement : moduleMethods) {
+ if (isAnnotationPresent(methodElement, Provides.class)) {
+ moduleProvidesMethodsBuilder.add(methodElement);
+ }
+ }
+ ImmutableSet<ExecutableElement> moduleProvidesMethods =
+ moduleProvidesMethodsBuilder.build();
+
+ if (Sets.difference(moduleProvidesMethods, validProvidesMethods).isEmpty()) {
+ // all of the provides methods in this module are valid!
+ // time to generate some factories!
+ ImmutableSet<ProvisionBinding> bindings = FluentIterable.from(moduleProvidesMethods)
+ .transform(new Function<ExecutableElement, ProvisionBinding>() {
+ @Override
+ public ProvisionBinding apply(ExecutableElement providesMethod) {
+ return provisionBindingFactory.forProvidesMethod(providesMethod,
+ providesMethod.getEnclosingElement().asType());
+ }
+ })
+ .toSet();
+
+ try {
+ for (ProvisionBinding binding : bindings) {
+ factoryGenerator.generate(binding);
+ }
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+ }
+ processedModuleElements.add(moduleElement);
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java b/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java
new file mode 100644
index 0000000..8b0c9a2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ModuleValidator.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Visibility;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.FluentIterable;
+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 dagger.Module;
+import dagger.producers.ProducerModule;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.Types;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+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.any;
+import static dagger.internal.codegen.ConfigurationAnnotations.getModuleIncludes;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.METHOD_OVERRIDES_PROVIDES_METHOD;
+import static dagger.internal.codegen.ErrorMessages.MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Module}s or {@link ProducerModule}s.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ModuleValidator {
+ private final Types types;
+ private final Elements elements;
+ private final Class<? extends Annotation> moduleClass;
+ private final ImmutableList<Class<? extends Annotation>> includedModuleClasses;
+ private final Class<? extends Annotation> methodClass;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ ModuleValidator(
+ Types types,
+ Elements elements,
+ MethodSignatureFormatter methodSignatureFormatter,
+ Class<? extends Annotation> moduleClass,
+ ImmutableList<Class<? extends Annotation>> includedModuleClasses,
+ Class<? extends Annotation> methodClass) {
+ this.types = types;
+ this.elements = elements;
+ this.moduleClass = moduleClass;
+ this.includedModuleClasses = includedModuleClasses;
+ this.methodClass = methodClass;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ ValidationReport<TypeElement> validate(final TypeElement subject) {
+ final ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ List<ExecutableElement> moduleMethods = ElementFilter.methodsIn(subject.getEnclosedElements());
+ ListMultimap<String, ExecutableElement> allMethodsByName = ArrayListMultimap.create();
+ ListMultimap<String, ExecutableElement> bindingMethodsByName = ArrayListMultimap.create();
+ for (ExecutableElement moduleMethod : moduleMethods) {
+ if (isAnnotationPresent(moduleMethod, methodClass)) {
+ bindingMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+ }
+ allMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+ }
+
+ validateModuleVisibility(subject, builder);
+ validateMethodsWithSameName(builder, bindingMethodsByName);
+ if (subject.getKind() != ElementKind.INTERFACE) {
+ validateProvidesOverrides(subject, builder, allMethodsByName, bindingMethodsByName);
+ }
+ validateModifiers(subject, builder);
+ validateReferencedModules(subject, builder);
+
+ // TODO(gak): port the dagger 1 module validation?
+ return builder.build();
+ }
+
+ 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_PARAMS_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(BINDING_METHOD_WITH_SAME_NAME, methodClass.getSimpleName()),
+ offendingMethod);
+ }
+ }
+ }
+ }
+
+ private void validateReferencedModules(
+ TypeElement subject, ValidationReport.Builder<TypeElement> builder) {
+ // Validate that all the modules we include are valid for inclusion.
+ AnnotationMirror mirror = getAnnotationMirror(subject, moduleClass).get();
+ ImmutableList<TypeMirror> includedTypes = getModuleIncludes(mirror);
+ validateReferencedModules(subject, builder, includedTypes);
+ }
+
+ /**
+ * Used by {@link ModuleValidator} & {@link ComponentValidator} to validate referenced modules.
+ */
+ void validateReferencedModules(
+ final TypeElement subject,
+ final ValidationReport.Builder<TypeElement> builder,
+ ImmutableList<TypeMirror> includedTypes) {
+ for (TypeMirror includedType : includedTypes) {
+ includedType.accept(
+ new SimpleTypeVisitor6<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror mirror, Void p) {
+ builder.addError(mirror + " is not a valid module type.", subject);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ final TypeElement element = MoreElements.asType(t.asElement());
+ if (!t.getTypeArguments().isEmpty()) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULE_MUST_NOT_HAVE_TYPE_PARAMS, element.getQualifiedName()),
+ subject);
+ }
+ boolean isIncludedModule =
+ any(
+ includedModuleClasses,
+ new Predicate<Class<? extends Annotation>>() {
+ @Override
+ public boolean apply(Class<? extends Annotation> otherClass) {
+ return MoreElements.isAnnotationPresent(element, otherClass);
+ }
+ });
+ if (!isIncludedModule) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULE_NOT_ANNOTATED,
+ element.getQualifiedName(),
+ (includedModuleClasses.size() > 1 ? "one of " : "")
+ + Joiner.on(", ")
+ .join(
+ FluentIterable.from(includedModuleClasses)
+ .transform(
+ new Function<Class<? extends Annotation>, String>() {
+ @Override
+ public String apply(
+ Class<? extends Annotation> otherClass) {
+ return "@" + otherClass.getSimpleName();
+ }
+ }))),
+ subject);
+ }
+ if (element.getModifiers().contains(ABSTRACT)) {
+ builder.addError(
+ String.format(
+ REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT, element.getQualifiedName()),
+ subject);
+ }
+ return null;
+ }
+ },
+ null);
+ }
+ }
+
+ private void validateProvidesOverrides(
+ TypeElement subject,
+ ValidationReport.Builder<TypeElement> builder,
+ ListMultimap<String, ExecutableElement> allMethodsByName,
+ ListMultimap<String, ExecutableElement> bindingMethodsByName) {
+ // For every @Provides 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 method marked @Provides in Parent, and "c" because Child is defining an @Provides
+ // method that overrides Parent.
+ TypeElement currentClass = subject;
+ TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).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 =
+ ElementFilter.methodsIn(currentClass.getEnclosedElements());
+ for (ExecutableElement superclassMethod : superclassMethods) {
+ String name = superclassMethod.getSimpleName().toString();
+ // For each method in the superclass, confirm our @Provides methods don't override it
+ for (ExecutableElement providesMethod : bindingMethodsByName.get(name)) {
+ if (!failedMethods.contains(providesMethod)
+ && elements.overrides(providesMethod, superclassMethod, subject)) {
+ failedMethods.add(providesMethod);
+ builder.addError(
+ String.format(
+ PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ methodClass.getSimpleName(),
+ methodSignatureFormatter.format(superclassMethod)),
+ providesMethod);
+ }
+ }
+ // For each @Provides method in superclass, confirm our methods don't override it.
+ if (isAnnotationPresent(superclassMethod, methodClass)) {
+ for (ExecutableElement method : allMethodsByName.get(name)) {
+ if (!failedMethods.contains(method)
+ && elements.overrides(method, superclassMethod, subject)) {
+ failedMethods.add(method);
+ builder.addError(
+ String.format(
+ METHOD_OVERRIDES_PROVIDES_METHOD,
+ methodClass.getSimpleName(),
+ methodSignatureFormatter.format(superclassMethod)),
+ method);
+ }
+ }
+ }
+ allMethodsByName.put(superclassMethod.getSimpleName().toString(), superclassMethod);
+ }
+ }
+ }
+
+ private void validateModuleVisibility(final TypeElement moduleElement,
+ final ValidationReport.Builder<?> reportBuilder) {
+ Visibility moduleVisibility = Visibility.ofElement(moduleElement);
+ if (moduleVisibility.equals(PRIVATE)) {
+ reportBuilder.addError("Modules cannot be private.", moduleElement);
+ } else if (effectiveVisibilityOfElement(moduleElement).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 (moduleVisibility.equals(PUBLIC)) {
+ ImmutableSet<Element> nonPublicModules = FluentIterable.from(getModuleIncludes(
+ getAnnotationMirror(moduleElement, moduleClass).get()))
+ .transform(new Function<TypeMirror, Element>() {
+ @Override public Element apply(TypeMirror input) {
+ return types.asElement(input);
+ }
+ })
+ .filter(new Predicate<Element>() {
+ @Override public boolean apply(Element input) {
+ return effectiveVisibilityOfElement(input).compareTo(PUBLIC) < 0;
+ }
+ })
+ .toSet();
+ if (!nonPublicModules.isEmpty()) {
+ reportBuilder.addError(
+ String.format(
+ "This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make %s public.",
+ formatListForErrorMessage(nonPublicModules.asList())),
+ moduleElement);
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ 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/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleGenerator.java b/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleGenerator.java
new file mode 100644
index 0000000..a4e020b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleGenerator.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import dagger.producers.monitoring.internal.MonitorCache;
+
+import java.util.Set;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.inject.Provider;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.element.Modifier.FINAL;
+
+/** Generates a monitoring module for use with production components. */
+final class MonitoringModuleGenerator extends SourceFileGenerator<TypeElement> {
+ private static final TypeName SET_OF_FACTORIES =
+ ParameterizedTypeName.create(
+ Set.class, ClassName.fromClass(ProductionComponentMonitor.Factory.class));
+
+ MonitoringModuleGenerator(Filer filer) {
+ super(filer);
+ }
+
+ @Override
+ ClassName nameGeneratedType(TypeElement componentElement) {
+ return SourceFiles.generatedMonitoringModuleName(componentElement);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(TypeElement componentElement) {
+ return ImmutableSet.of(componentElement);
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(TypeElement componentElement) {
+ return Optional.of(componentElement);
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, TypeElement componentElement) {
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+ ClassWriter classWriter = writer.addClass(generatedTypeName.simpleName());
+ classWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ classWriter.annotate(Module.class);
+ classWriter.addModifiers(FINAL);
+
+ // TODO(beder): Replace this default set binding with EmptyCollections when it exists.
+ MethodWriter emptySetBindingMethod =
+ classWriter.addMethod(SET_OF_FACTORIES, "defaultSetOfFactories");
+ emptySetBindingMethod.addModifiers(STATIC);
+ emptySetBindingMethod.annotate(Provides.class).setMember("type", Provides.Type.SET_VALUES);
+ emptySetBindingMethod
+ .body()
+ .addSnippet("return %s.of();", ClassName.fromClass(ImmutableSet.class));
+
+ FieldWriter providerField = classWriter.addField(MonitorCache.class, "monitorCache");
+ providerField.addModifiers(PRIVATE, FINAL);
+ providerField.setInitializer("new %s()", ClassName.fromClass(MonitorCache.class));
+ MethodWriter monitorMethod = classWriter.addMethod(ProductionComponentMonitor.class, "monitor");
+ monitorMethod.annotate(Provides.class);
+ monitorMethod.addParameter(
+ ParameterizedTypeName.create(Provider.class, ClassName.fromTypeElement(componentElement)),
+ "component");
+ monitorMethod.addParameter(
+ ParameterizedTypeName.create(Provider.class, SET_OF_FACTORIES), "factories");
+ monitorMethod.body().addSnippet("return monitorCache.monitor(component, factories);");
+
+ return ImmutableSet.of(writer);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java
new file mode 100644
index 0000000..91b10e7
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import static javax.lang.model.util.ElementFilter.typesIn;
+
+/**
+ * A processing step that is responsible for generating a special module for a
+ * {@link ProductionComponent}.
+ */
+final class MonitoringModuleProcessingStep implements ProcessingStep {
+ private final Messager messager;
+ private final MonitoringModuleGenerator monitoringModuleGenerator;
+
+ MonitoringModuleProcessingStep(
+ Messager messager, MonitoringModuleGenerator monitoringModuleGenerator) {
+ this.messager = messager;
+ this.monitoringModuleGenerator = monitoringModuleGenerator;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(ProductionComponent.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ for (TypeElement element : typesIn(elementsByAnnotation.get(ProductionComponent.class))) {
+ try {
+ monitoringModuleGenerator.generate(element);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java
new file mode 100644
index 0000000..90a0337
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducerFactoryGenerator.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+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.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Provides.Type;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.ConstructorWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.Produces;
+import dagger.producers.internal.AbstractProducer;
+import dagger.producers.internal.Producers;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import java.util.List;
+import java.util.concurrent.Executor;
+import javax.annotation.Generated;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeMirror;
+
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.writer.Snippet.makeParametersSnippet;
+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;
+
+/**
+ * Generates {@link Producer} implementations from {@link ProductionBinding} instances.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
+ private final DependencyRequestMapper dependencyRequestMapper;
+
+ ProducerFactoryGenerator(Filer filer, DependencyRequestMapper dependencyRequestMapper) {
+ super(filer);
+ this.dependencyRequestMapper = dependencyRequestMapper;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProductionBinding binding) {
+ return generatedClassNameForBinding(binding);
+ }
+
+ @Override
+ Iterable<? extends Element> getOriginatingElements(ProductionBinding binding) {
+ return ImmutableSet.of(binding.bindingElement());
+ }
+
+ @Override
+ Optional<? extends Element> getElementForErrorReporting(ProductionBinding binding) {
+ return Optional.of(binding.bindingElement());
+ }
+
+ @Override
+ ImmutableSet<JavaWriter> write(ClassName generatedTypeName, ProductionBinding binding) {
+ TypeMirror keyType = binding.productionType().equals(Type.MAP)
+ ? Util.getProvidedValueTypeOfMap(MoreTypes.asDeclared(binding.key().type()))
+ : binding.key().type();
+ TypeName providedTypeName = TypeNames.forTypeMirror(keyType);
+ TypeName futureTypeName = ParameterizedTypeName.create(
+ ClassName.fromClass(ListenableFuture.class), providedTypeName);
+ JavaWriter writer = JavaWriter.inPackage(generatedTypeName.packageName());
+
+ ClassWriter factoryWriter = writer.addClass(generatedTypeName.simpleName());
+ ConstructorWriter constructorWriter = factoryWriter.addConstructor();
+ constructorWriter.addModifiers(PUBLIC);
+
+ ImmutableMap<BindingKey, FrameworkField> fields =
+ SourceFiles.generateBindingFieldsForDependencies(
+ dependencyRequestMapper, binding.implicitDependencies());
+
+ constructorWriter
+ .body()
+ .addSnippet(
+ "super(%s, %s.create(%s.class));",
+ fields.get(binding.monitorRequest().get().bindingKey()).name(),
+ ClassName.fromClass(ProducerToken.class),
+ factoryWriter.name());
+
+ if (!binding.bindingElement().getModifiers().contains(STATIC)) {
+ factoryWriter.addField(binding.bindingTypeElement(), "module")
+ .addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(binding.bindingTypeElement(), "module");
+ constructorWriter.body()
+ .addSnippet("assert module != null;")
+ .addSnippet("this.module = module;");
+ }
+
+ factoryWriter.addField(Executor.class, "executor")
+ .addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(Executor.class, "executor");
+ constructorWriter.body()
+ .addSnippet("assert executor != null;")
+ .addSnippet("this.executor = executor;");
+
+ factoryWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getName());
+ factoryWriter.addModifiers(PUBLIC);
+ factoryWriter.addModifiers(FINAL);
+ factoryWriter.setSuperclass(
+ ParameterizedTypeName.create(AbstractProducer.class, providedTypeName));
+
+ MethodWriter computeMethodWriter = factoryWriter.addMethod(futureTypeName, "compute");
+ computeMethodWriter.annotate(Override.class);
+ computeMethodWriter.addModifiers(PROTECTED);
+ computeMethodWriter.addParameter(ProducerMonitor.class, "monitor").addModifiers(FINAL);
+
+ for (FrameworkField bindingField : fields.values()) {
+ TypeName fieldType = bindingField.frameworkType();
+ FieldWriter field = factoryWriter.addField(fieldType, bindingField.name());
+ field.addModifiers(PRIVATE, FINAL);
+ constructorWriter.addParameter(field.type(), field.name());
+ constructorWriter.body()
+ .addSnippet("assert %s != null;", field.name())
+ .addSnippet("this.%1$s = %1$s;", field.name());
+ }
+
+ boolean returnsFuture =
+ binding.bindingKind().equals(ContributionBinding.Kind.FUTURE_PRODUCTION);
+ ImmutableList<DependencyRequest> asyncDependencies =
+ FluentIterable.from(binding.implicitDependencies())
+ .filter(
+ new Predicate<DependencyRequest>() {
+ @Override
+ public boolean apply(DependencyRequest dependency) {
+ return isAsyncDependency(dependency);
+ }
+ })
+ .toList();
+
+ for (DependencyRequest dependency : asyncDependencies) {
+ ParameterizedTypeName futureType = ParameterizedTypeName.create(
+ ClassName.fromClass(ListenableFuture.class),
+ asyncDependencyType(dependency));
+ String name = fields.get(dependency.bindingKey()).name();
+ Snippet futureAccess = Snippet.format("%s.get()", name);
+ computeMethodWriter
+ .body()
+ .addSnippet(
+ "%s %sFuture = %s;",
+ futureType,
+ name,
+ dependency.kind().equals(DependencyRequest.Kind.PRODUCED)
+ ? Snippet.format(
+ "%s.createFutureProduced(%s)",
+ ClassName.fromClass(Producers.class),
+ futureAccess)
+ : futureAccess);
+ }
+
+ FutureTransform futureTransform = FutureTransform.create(fields, binding, asyncDependencies);
+ Snippet transformSnippet =
+ Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "new %1$s<%2$s, %3$s>() {",
+ " %4$s",
+ " @Override public %5$s apply(%2$s %6$s) %7$s {",
+ " %8$s",
+ " }",
+ "}"),
+ ClassName.fromClass(AsyncFunction.class),
+ futureTransform.applyArgType(),
+ providedTypeName,
+ futureTransform.hasUncheckedCast()
+ ? "@SuppressWarnings(\"unchecked\") // safe by specification"
+ : "",
+ futureTypeName,
+ futureTransform.applyArgName(),
+ getThrowsClause(binding.thrownTypes()),
+ getInvocationSnippet(!returnsFuture, binding, futureTransform.parameterSnippets()));
+ computeMethodWriter
+ .body()
+ .addSnippet(
+ "return %s.transform(%s, %s, executor);",
+ ClassName.fromClass(Futures.class),
+ futureTransform.futureSnippet(),
+ transformSnippet);
+
+ // TODO(gak): write a sensible toString
+ return ImmutableSet.of(writer);
+ }
+
+ /** Represents the transformation of an input future by a producer method. */
+ abstract static class FutureTransform {
+ protected final ImmutableMap<BindingKey, FrameworkField> fields;
+ protected final ProductionBinding binding;
+
+ FutureTransform(ImmutableMap<BindingKey, FrameworkField> fields, ProductionBinding binding) {
+ this.fields = fields;
+ this.binding = binding;
+ }
+
+ /** The snippet representing the future that should be transformed. */
+ abstract Snippet futureSnippet();
+
+ /** 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 snippets to be passed to the produces method itself. */
+ abstract ImmutableList<Snippet> parameterSnippets();
+
+ /** Whether the transform method has an unchecked cast. */
+ boolean hasUncheckedCast() {
+ return false;
+ }
+
+ static FutureTransform create(
+ ImmutableMap<BindingKey, FrameworkField> 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<BindingKey, FrameworkField> fields, ProductionBinding binding) {
+ super(fields, binding);
+ }
+
+ @Override
+ Snippet futureSnippet() {
+ return Snippet.format(
+ "%s.<%s>immediateFuture(null)",
+ ClassName.fromClass(Futures.class),
+ ClassName.fromClass(Void.class));
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return ClassName.fromClass(Void.class);
+ }
+
+ @Override
+ String applyArgName() {
+ return "ignoredVoidArg";
+ }
+
+ @Override
+ ImmutableList<Snippet> parameterSnippets() {
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ parameterSnippets.add(
+ frameworkTypeUsageStatement(
+ Snippet.format(
+ "%s", fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ return parameterSnippets.build();
+ }
+ }
+
+ static final class SingleArgFutureTransform extends FutureTransform {
+ private final DependencyRequest asyncDependency;
+
+ SingleArgFutureTransform(
+ ImmutableMap<BindingKey, FrameworkField> fields,
+ ProductionBinding binding,
+ DependencyRequest asyncDependency) {
+ super(fields, binding);
+ this.asyncDependency = asyncDependency;
+ }
+
+ @Override
+ Snippet futureSnippet() {
+ return Snippet.format("%s", fields.get(asyncDependency.bindingKey()).name() + "Future");
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return asyncDependencyType(asyncDependency);
+ }
+
+ @Override
+ String applyArgName() {
+ return asyncDependency.requestElement().getSimpleName().toString();
+ }
+
+ @Override
+ ImmutableList<Snippet> parameterSnippets() {
+ ImmutableList.Builder<Snippet> parameterSnippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ // We really want to compare instances here, because asyncDependency is an element in the
+ // set binding.dependencies().
+ if (dependency == asyncDependency) {
+ parameterSnippets.add(Snippet.format("%s", applyArgName()));
+ } else {
+ parameterSnippets.add(
+ frameworkTypeUsageStatement(
+ Snippet.format(
+ "%s", fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ }
+ return parameterSnippets.build();
+ }
+ }
+
+ static final class MultiArgFutureTransform extends FutureTransform {
+ private final ImmutableList<DependencyRequest> asyncDependencies;
+
+ MultiArgFutureTransform(
+ ImmutableMap<BindingKey, FrameworkField> fields,
+ ProductionBinding binding,
+ ImmutableList<DependencyRequest> asyncDependencies) {
+ super(fields, binding);
+ this.asyncDependencies = asyncDependencies;
+ }
+
+ @Override
+ Snippet futureSnippet() {
+ return Snippet.format(
+ "%s.<%s>allAsList(%s)",
+ ClassName.fromClass(Futures.class),
+ ClassName.fromClass(Object.class),
+ makeParametersSnippet(
+ FluentIterable.from(asyncDependencies)
+ .transform(DependencyRequest.BINDING_KEY_FUNCTION)
+ .transform(
+ new Function<BindingKey, Snippet>() {
+ @Override
+ public Snippet apply(BindingKey bindingKey) {
+ return Snippet.format("%s", fields.get(bindingKey).name() + "Future");
+ }
+ })));
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return ParameterizedTypeName.create(
+ ClassName.fromClass(List.class), ClassName.fromClass(Object.class));
+ }
+
+ @Override
+ String applyArgName() {
+ return "args";
+ }
+
+ @Override
+ ImmutableList<Snippet> parameterSnippets() {
+ return getParameterSnippets(binding, fields, applyArgName());
+ }
+
+ @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 = TypeNames.forTypeMirror(dependency.key().type());
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return keyName;
+ case PRODUCED:
+ return ParameterizedTypeName.create(ClassName.fromClass(Produced.class), keyName);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static ImmutableList<Snippet> getParameterSnippets(
+ ProductionBinding binding,
+ ImmutableMap<BindingKey, FrameworkField> fields,
+ String listArgName) {
+ int argIndex = 0;
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.dependencies()) {
+ if (isAsyncDependency(dependency)) {
+ snippets.add(Snippet.format(
+ "(%s) %s.get(%s)",
+ asyncDependencyType(dependency),
+ listArgName,
+ argIndex));
+ argIndex++;
+ } else {
+ snippets.add(frameworkTypeUsageStatement(
+ Snippet.format("%s", fields.get(dependency.bindingKey()).name()), dependency.kind()));
+ }
+ }
+ return snippets.build();
+ }
+
+ /**
+ * Creates a snippet for the invocation of the producer method from the module, which should be
+ * used entirely within a method body.
+ *
+ * @param wrapWithFuture If true, wraps the result of the call to the producer method
+ * in an immediate future.
+ * @param binding The binding to generate the invocation snippet for.
+ * @param parameterSnippets The snippets for all the parameters to the producer method.
+ */
+ private Snippet getInvocationSnippet(
+ boolean wrapWithFuture, ProductionBinding binding, ImmutableList<Snippet> parameterSnippets) {
+ Snippet moduleSnippet = Snippet.format("%s.%s(%s)",
+ binding.bindingElement().getModifiers().contains(STATIC)
+ ? ClassName.fromTypeElement(binding.bindingTypeElement())
+ : "module",
+ binding.bindingElement().getSimpleName(),
+ makeParametersSnippet(parameterSnippets));
+
+ // NOTE(beder): We don't worry about catching exeptions from the monitor methods themselves
+ // because we'll wrap all monitoring in non-throwing monitors before we pass them to the
+ // factories.
+ ImmutableList.Builder<Snippet> snippets = ImmutableList.builder();
+ snippets.add(Snippet.format("monitor.methodStarting();"));
+
+ final Snippet valueSnippet;
+ if (binding.productionType().equals(Produces.Type.SET)) {
+ if (binding.bindingKind().equals(ContributionBinding.Kind.FUTURE_PRODUCTION)) {
+ valueSnippet =
+ Snippet.format(
+ "%s.createFutureSingletonSet(%s)",
+ ClassName.fromClass(Producers.class),
+ moduleSnippet);
+ } else {
+ valueSnippet =
+ Snippet.format("%s.of(%s)", ClassName.fromClass(ImmutableSet.class), moduleSnippet);
+ }
+ } else {
+ valueSnippet = moduleSnippet;
+ }
+ Snippet returnSnippet =
+ wrapWithFuture
+ ? Snippet.format(
+ "%s.<%s>immediateFuture(%s)",
+ ClassName.fromClass(Futures.class),
+ TypeNames.forTypeMirror(binding.key().type()),
+ valueSnippet)
+ : valueSnippet;
+ return Snippet.format(
+ Joiner.on('\n')
+ .join(
+ "monitor.methodStarting();",
+ "try {",
+ " return %s;",
+ "} finally {",
+ " monitor.methodFinished();",
+ "}"),
+ returnSnippet);
+ }
+
+ /**
+ * Creates a Snippet for the throws clause.
+ *
+ * @param thrownTypes the list of thrown types.
+ */
+ private Snippet getThrowsClause(List<? extends TypeMirror> thrownTypes) {
+ if (thrownTypes.isEmpty()) {
+ return Snippet.format("");
+ }
+ return Snippet.format("throws %s ",
+ Snippet.makeParametersSnippet(FluentIterable
+ .from(thrownTypes)
+ .transform(new Function<TypeMirror, Snippet>() {
+ @Override public Snippet apply(TypeMirror thrownType) {
+ return Snippet.format("%s", TypeNames.forTypeMirror(thrownType));
+ }
+ })
+ .toList()));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java
new file mode 100644
index 0000000..cc167e5
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducerModuleProcessingStep.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.common.MoreElements;
+import com.google.auto.common.SuperficialValidation;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * An annotation processor for generating Dagger implementation code based on the
+ * {@link ProducerModule} (and {@link Produces}) annotation.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+final class ProducerModuleProcessingStep implements ProcessingStep {
+ private final Messager messager;
+ private final ModuleValidator moduleValidator;
+ private final ProducesMethodValidator producesMethodValidator;
+ private final ProductionBinding.Factory productionBindingFactory;
+ private final ProducerFactoryGenerator factoryGenerator;
+ private final Set<Element> processedModuleElements = Sets.newLinkedHashSet();
+
+ ProducerModuleProcessingStep(
+ Messager messager,
+ ModuleValidator moduleValidator,
+ ProducesMethodValidator producesMethodValidator,
+ ProductionBinding.Factory productionBindingFactory,
+ ProducerFactoryGenerator factoryGenerator) {
+ this.messager = messager;
+ this.moduleValidator = moduleValidator;
+ this.producesMethodValidator = producesMethodValidator;
+ this.productionBindingFactory = productionBindingFactory;
+ this.factoryGenerator = factoryGenerator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(Produces.class, ProducerModule.class);
+ }
+
+ @Override
+ public Set<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ // first, check and collect all produces methods
+ ImmutableSet.Builder<ExecutableElement> validProducesMethodsBuilder = ImmutableSet.builder();
+ for (Element producesElement : elementsByAnnotation.get(Produces.class)) {
+ if (producesElement.getKind().equals(METHOD)) {
+ ExecutableElement producesMethodElement = (ExecutableElement) producesElement;
+ ValidationReport<ExecutableElement> methodReport =
+ producesMethodValidator.validate(producesMethodElement);
+ methodReport.printMessagesTo(messager);
+ if (methodReport.isClean()) {
+ validProducesMethodsBuilder.add(producesMethodElement);
+ }
+ }
+ }
+ ImmutableSet<ExecutableElement> validProducesMethods = validProducesMethodsBuilder.build();
+
+ // process each module
+ for (Element moduleElement :
+ Sets.difference(elementsByAnnotation.get(ProducerModule.class),
+ processedModuleElements)) {
+ if (SuperficialValidation.validateElement(moduleElement)) {
+ ValidationReport<TypeElement> report =
+ moduleValidator.validate(MoreElements.asType(moduleElement));
+ report.printMessagesTo(messager);
+
+ if (report.isClean()) {
+ ImmutableSet.Builder<ExecutableElement> moduleProducesMethodsBuilder =
+ ImmutableSet.builder();
+ List<ExecutableElement> moduleMethods =
+ ElementFilter.methodsIn(moduleElement.getEnclosedElements());
+ for (ExecutableElement methodElement : moduleMethods) {
+ if (isAnnotationPresent(methodElement, Produces.class)) {
+ moduleProducesMethodsBuilder.add(methodElement);
+ }
+ }
+ ImmutableSet<ExecutableElement> moduleProducesMethods =
+ moduleProducesMethodsBuilder.build();
+
+ if (Sets.difference(moduleProducesMethods, validProducesMethods).isEmpty()) {
+ // all of the produces methods in this module are valid!
+ // time to generate some factories!
+ ImmutableSet<ProductionBinding> bindings = FluentIterable.from(moduleProducesMethods)
+ .transform(new Function<ExecutableElement, ProductionBinding>() {
+ @Override
+ public ProductionBinding apply(ExecutableElement producesMethod) {
+ return productionBindingFactory.forProducesMethod(producesMethod,
+ producesMethod.getEnclosingElement().asType());
+ }
+ })
+ .toSet();
+
+ try {
+ for (ProductionBinding binding : bindings) {
+ factoryGenerator.generate(binding);
+ }
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+ }
+
+ processedModuleElements.add(moduleElement);
+ }
+ }
+ return ImmutableSet.of();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java
new file mode 100644
index 0000000..b0b4df1
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProducesMethodValidator.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_MAP_HAS_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_MULTIPLE_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_NO_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RAW_FUTURE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.MapKeys.getMapKeys;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.type.TypeKind.ARRAY;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Produces} methods.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+// TODO(user): Consider unifying this with the ProvidesMethodValidator after Provides.Type and
+// Produces.Type are reconciled.
+final class ProducesMethodValidator {
+ private final Elements elements;
+
+ ProducesMethodValidator(Elements elements) {
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement producesMethodElement) {
+ ValidationReport.Builder<ExecutableElement> builder =
+ ValidationReport.about(producesMethodElement);
+
+ Produces producesAnnotation = producesMethodElement.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+
+ Element enclosingElement = producesMethodElement.getEnclosingElement();
+ if (!isAnnotationPresent(enclosingElement, ProducerModule.class)) {
+ builder.addError(
+ formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE), producesMethodElement);
+ }
+
+ if (!producesMethodElement.getTypeParameters().isEmpty()) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER), producesMethodElement);
+ }
+
+ Set<Modifier> modifiers = producesMethodElement.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_PRIVATE), producesMethodElement);
+ }
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_ABSTRACT), producesMethodElement);
+ }
+
+ TypeMirror returnType = producesMethodElement.getReturnType();
+ TypeKind returnTypeKind = returnType.getKind();
+ if (returnTypeKind.equals(VOID)) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE), producesMethodElement);
+ }
+
+ // check mapkey is right
+ if (!producesAnnotation.type().equals(Produces.Type.MAP)
+ && !getMapKeys(producesMethodElement).isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_NOT_MAP_HAS_MAP_KEY), producesMethodElement);
+ }
+
+ ProvidesMethodValidator.validateMethodQualifiers(builder, producesMethodElement);
+
+ switch (producesAnnotation.type()) {
+ case UNIQUE: // fall through
+ case SET:
+ validateSingleReturnType(builder, returnType);
+ break;
+ case MAP:
+ validateSingleReturnType(builder, returnType);
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(producesMethodElement);
+ switch (mapKeys.size()) {
+ case 0:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_NO_MAP_KEY), producesMethodElement);
+ break;
+ case 1:
+ break;
+ default:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_MULTIPLE_MAP_KEY), producesMethodElement);
+ break;
+ }
+ break;
+ case SET_VALUES:
+ if (returnTypeKind.equals(DECLARED)
+ && MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
+ DeclaredType declaredReturnType = MoreTypes.asDeclared(returnType);
+ if (!declaredReturnType.getTypeArguments().isEmpty()) {
+ validateSetType(builder, Iterables.getOnlyElement(
+ declaredReturnType.getTypeArguments()));
+ }
+ } else {
+ validateSetType(builder, returnType);
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ return builder.build();
+ }
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, Produces.class.getSimpleName());
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, Produces.class.getSimpleName(), ProducerModule.class.getSimpleName());
+ }
+
+ private void validateKeyType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ TypeKind kind = type.getKind();
+ if (!(kind.isPrimitive() || kind.equals(DECLARED) || kind.equals(ARRAY))) {
+ reportBuilder.addError(PRODUCES_METHOD_RETURN_TYPE, reportBuilder.getSubject());
+ }
+ }
+
+ private void validateSingleReturnType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ if (type.getKind().equals(DECLARED) && MoreTypes.isTypeOf(ListenableFuture.class, type)) {
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ if (declaredType.getTypeArguments().isEmpty()) {
+ reportBuilder.addError(PRODUCES_METHOD_RAW_FUTURE, reportBuilder.getSubject());
+ } else {
+ validateKeyType(reportBuilder, Iterables.getOnlyElement(declaredType.getTypeArguments()));
+ }
+ } else {
+ validateKeyType(reportBuilder, type);
+ }
+ }
+
+ private void validateSetType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ if (!type.getKind().equals(DECLARED)) {
+ reportBuilder.addError(PRODUCES_METHOD_SET_VALUES_RETURN_SET, reportBuilder.getSubject());
+ return;
+ }
+
+ // TODO(gak): should we allow "covariant return" for set values?
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ if (!declaredType.asElement().equals(getSetElement())) {
+ reportBuilder.addError(PRODUCES_METHOD_SET_VALUES_RETURN_SET, reportBuilder.getSubject());
+ } else if (declaredType.getTypeArguments().isEmpty()) {
+ reportBuilder.addError(
+ formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET), reportBuilder.getSubject());
+ } else {
+ validateSingleReturnType(reportBuilder,
+ Iterables.getOnlyElement(declaredType.getTypeArguments()));
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java
new file mode 100644
index 0000000..1666fbf
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionBinding.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Provides;
+import dagger.producers.Produces;
+import java.util.Set;
+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;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be produced. New instances
+ * should be created using an instance of the {@link Factory}.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+@AutoValue
+abstract class ProductionBinding extends ContributionBinding {
+
+ @Override
+ Binding.Type bindingType() {
+ return Binding.Type.PRODUCTION;
+ }
+
+ @Override
+ Provides.Type provisionType() {
+ return Provides.Type.valueOf(productionType().name());
+ }
+
+ @Override
+ Set<DependencyRequest> implicitDependencies() {
+ // Similar optimizations to ContributionBinding.implicitDependencies().
+ if (!monitorRequest().isPresent()) {
+ return super.implicitDependencies();
+ } else {
+ return Sets.union(monitorRequest().asSet(), super.implicitDependencies());
+ }
+ }
+
+ /** Returns provision type that was used to bind the key. */
+ abstract Produces.Type productionType();
+
+ /** Returns the list of types in the throws clause of the method. */
+ abstract ImmutableList<? extends TypeMirror> thrownTypes();
+
+ /** If this production requires a monitor, this will be the corresponding request. */
+ abstract Optional<DependencyRequest> monitorRequest();
+
+ @Override
+ ContributionType contributionType() {
+ switch (productionType()) {
+ case SET:
+ case SET_VALUES:
+ return ContributionType.SET;
+ case MAP:
+ return ContributionType.MAP;
+ case UNIQUE:
+ return ContributionType.UNIQUE;
+ default:
+ throw new AssertionError("Unknown production type: " + productionType());
+ }
+ }
+
+ static final class Factory {
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(
+ Types types, Key.Factory keyFactory, DependencyRequest.Factory dependencyRequestFactory) {
+ this.types = types;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ ProductionBinding forProducesMethod(
+ ExecutableElement producesMethod, TypeMirror contributedBy) {
+ checkNotNull(producesMethod);
+ checkArgument(producesMethod.getKind().equals(METHOD));
+ checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED));
+ Produces producesAnnotation = producesMethod.getAnnotation(Produces.class);
+ checkArgument(producesAnnotation != null);
+ DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy);
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredContainer, producesMethod));
+ Key key = keyFactory.forProducesMethod(resolvedMethod, producesMethod);
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ declaredContainer,
+ producesMethod.getParameters(),
+ resolvedMethod.getParameterTypes());
+ DependencyRequest monitorRequest =
+ dependencyRequestFactory.forProductionComponentMonitorProvider();
+ Kind kind = MoreTypes.isTypeOf(ListenableFuture.class, producesMethod.getReturnType())
+ ? Kind.FUTURE_PRODUCTION
+ : Kind.IMMEDIATE;
+ return new AutoValue_ProductionBinding(
+ key,
+ producesMethod,
+ dependencies,
+ findBindingPackage(key),
+ false,
+ ConfigurationAnnotations.getNullableType(producesMethod),
+ Optional.of(MoreTypes.asTypeElement(declaredContainer)),
+ Optional.<DependencyRequest>absent(),
+ kind,
+ producesAnnotation.type(),
+ ImmutableList.copyOf(producesMethod.getThrownTypes()),
+ Optional.of(monitorRequest));
+ }
+
+ ProductionBinding implicitMapOfProducerBinding(DependencyRequest mapOfValueRequest) {
+ checkNotNull(mapOfValueRequest);
+ Optional<Key> implicitMapOfProducerKey =
+ keyFactory.implicitMapProducerKeyFrom(mapOfValueRequest.key());
+ checkArgument(
+ implicitMapOfProducerKey.isPresent(), "%s is not for a Map<K, V>", mapOfValueRequest);
+ DependencyRequest implicitMapOfProducerRequest =
+ dependencyRequestFactory.forImplicitMapBinding(
+ mapOfValueRequest, implicitMapOfProducerKey.get());
+ return new AutoValue_ProductionBinding(
+ mapOfValueRequest.key(),
+ implicitMapOfProducerRequest.requestElement(),
+ ImmutableSet.of(implicitMapOfProducerRequest),
+ findBindingPackage(mapOfValueRequest.key()),
+ false,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Optional.<DependencyRequest>absent(),
+ Kind.SYNTHETIC,
+ Produces.Type.MAP,
+ ImmutableList.<TypeMirror>of(),
+ Optional.<DependencyRequest>absent());
+ }
+
+ ProductionBinding forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ checkArgument(componentMethod.getParameters().isEmpty());
+ checkArgument(MoreTypes.isTypeOf(ListenableFuture.class, componentMethod.getReturnType()));
+ return new AutoValue_ProductionBinding(
+ keyFactory.forProductionComponentMethod(componentMethod),
+ componentMethod,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Optional.<DependencyRequest>absent(),
+ Kind.COMPONENT_PRODUCTION,
+ Produces.Type.UNIQUE,
+ ImmutableList.copyOf(componentMethod.getThrownTypes()),
+ Optional.<DependencyRequest>absent());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java
new file mode 100644
index 0000000..0581b1b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentProcessingStep.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A {@link ProcessingStep} that is responsible for dealing with the {@link ProductionComponent}
+ * annotation as part of the {@link ComponentProcessor}.
+ *
+ * @author Jesse Beder
+ */
+final class ProductionComponentProcessingStep extends AbstractComponentProcessingStep {
+ private final Messager messager;
+ private final ProductionComponentValidator componentValidator;
+ private final BuilderValidator componentBuilderValidator;
+
+ ProductionComponentProcessingStep(
+ Messager messager,
+ ProductionComponentValidator componentValidator,
+ BuilderValidator componentBuilderValidator,
+ ComponentHierarchyValidator componentHierarchyValidator,
+ BindingGraphValidator bindingGraphValidator,
+ ComponentDescriptor.Factory componentDescriptorFactory,
+ BindingGraph.Factory bindingGraphFactory,
+ ComponentGenerator componentGenerator) {
+ super(
+ ProductionComponent.class,
+ messager,
+ componentHierarchyValidator,
+ bindingGraphValidator,
+ componentDescriptorFactory,
+ bindingGraphFactory,
+ componentGenerator);
+ this.messager = messager;
+ this.componentValidator = componentValidator;
+ this.componentBuilderValidator = componentBuilderValidator;
+ }
+
+ @Override
+ public Set<Class<? extends Annotation>> annotations() {
+ return ImmutableSet.<Class<? extends Annotation>>of(
+ ProductionComponent.class, ProductionComponent.Builder.class);
+ }
+
+ // TODO(beder): Move common logic into the AbstractComponentProcessingStep when implementing
+ // production subcomponents.
+ @Override
+ protected ComponentElementValidator componentElementValidator(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ final Map<Element, ValidationReport<TypeElement>> builderReportsByComponent =
+ processComponentBuilders(elementsByAnnotation.get(ProductionComponent.Builder.class));
+ return new ComponentElementValidator() {
+ @Override
+ boolean validateComponent(TypeElement componentTypeElement, Messager messager) {
+ ValidationReport<TypeElement> validationReport =
+ componentValidator.validate(componentTypeElement);
+ validationReport.printMessagesTo(messager);
+ if (!validationReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> builderReport = builderReportsByComponent.get(componentTypeElement);
+ return builderReport == null || builderReport.isClean();
+ }
+ };
+ }
+
+ private Map<Element, ValidationReport<TypeElement>> processComponentBuilders(
+ Set<? extends Element> componentBuilderElements) {
+ Map<Element, ValidationReport<TypeElement>> builderReportsByComponent = Maps.newHashMap();
+ for (Element element : componentBuilderElements) {
+ ValidationReport<TypeElement> report =
+ componentBuilderValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ builderReportsByComponent.put(element.getEnclosingElement(), report);
+ }
+ return builderReportsByComponent;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java
new file mode 100644
index 0000000..2e2291d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProductionComponentValidator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.ImmutableList;
+import dagger.Module;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
+import static javax.lang.model.element.ElementKind.CLASS;
+import static javax.lang.model.element.ElementKind.INTERFACE;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+/**
+ * Performs superficial validation of the contract of the {@link ProductionComponent} annotation.
+ *
+ * @author Jesse Beder
+ */
+final class ProductionComponentValidator {
+ ValidationReport<TypeElement> validate(final TypeElement subject) {
+ final ValidationReport.Builder<TypeElement> builder = ValidationReport.about(subject);
+
+ if (!subject.getKind().equals(INTERFACE)
+ && !(subject.getKind().equals(CLASS) && subject.getModifiers().contains(ABSTRACT))) {
+ builder.addError(
+ "@ProductionComponent may only be applied to an interface or abstract class", subject);
+ }
+
+ AnnotationMirror componentMirror =
+ getAnnotationMirror(subject, ProductionComponent.class).get();
+ ImmutableList<TypeMirror> moduleTypes = getComponentModules(componentMirror);
+
+ // TODO(gak): make unused modules an error
+ for (TypeMirror moduleType : moduleTypes) {
+ moduleType.accept(
+ new SimpleTypeVisitor6<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror mirror, Void p) {
+ builder.addError(mirror + " is not a valid module type.", subject);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ checkState(t.getTypeArguments().isEmpty());
+ TypeElement moduleElement = MoreElements.asType(t.asElement());
+ if (!getAnnotationMirror(moduleElement, Module.class).isPresent()
+ && !getAnnotationMirror(moduleElement, ProducerModule.class).isPresent()) {
+ builder.addError(
+ moduleElement.getQualifiedName()
+ + " is listed as a module, but is not annotated with @Module or"
+ + " @ProducerModule",
+ subject);
+ }
+ return null;
+ }
+ },
+ null);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java b/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java
new file mode 100644
index 0000000..e9c8b16
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProvidesMethodValidator.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Iterables;
+import dagger.Module;
+import dagger.Provides;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_MAP_HAS_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_MULTIPLE_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_NO_MAP_KEY;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.MapKeys.getMapKeys;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.type.TypeKind.ARRAY;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Provides} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class ProvidesMethodValidator {
+ private final Elements elements;
+
+ ProvidesMethodValidator(Elements elements) {
+ this.elements = checkNotNull(elements);
+ }
+
+ private TypeElement getSetElement() {
+ return elements.getTypeElement(Set.class.getCanonicalName());
+ }
+
+ ValidationReport<ExecutableElement> validate(ExecutableElement providesMethodElement) {
+ ValidationReport.Builder<ExecutableElement> builder =
+ ValidationReport.about(providesMethodElement);
+
+ Provides providesAnnotation = providesMethodElement.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+
+ Element enclosingElement = providesMethodElement.getEnclosingElement();
+ if (!isAnnotationPresent(enclosingElement, Module.class)) {
+ builder.addError(
+ formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE), providesMethodElement);
+ }
+
+ if (!providesMethodElement.getTypeParameters().isEmpty()) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER), providesMethodElement);
+ }
+
+ Set<Modifier> modifiers = providesMethodElement.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_PRIVATE), providesMethodElement);
+ }
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError(formatErrorMessage(BINDING_METHOD_ABSTRACT), providesMethodElement);
+ }
+
+ TypeMirror returnType = providesMethodElement.getReturnType();
+ TypeKind returnTypeKind = returnType.getKind();
+ if (returnTypeKind.equals(VOID)) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE), providesMethodElement);
+ }
+
+ // check mapkey is right
+ if (!providesAnnotation.type().equals(Provides.Type.MAP)
+ && !getMapKeys(providesMethodElement).isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_NOT_MAP_HAS_MAP_KEY), providesMethodElement);
+ }
+
+ validateMethodQualifiers(builder, providesMethodElement);
+
+ switch (providesAnnotation.type()) {
+ case UNIQUE: // fall through
+ case SET:
+ validateKeyType(builder, returnType);
+ break;
+ case MAP:
+ validateKeyType(builder, returnType);
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(providesMethodElement);
+ switch (mapKeys.size()) {
+ case 0:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_NO_MAP_KEY), providesMethodElement);
+ break;
+ case 1:
+ break;
+ default:
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_WITH_MULTIPLE_MAP_KEY), providesMethodElement);
+ break;
+ }
+ break;
+ case SET_VALUES:
+ if (!returnTypeKind.equals(DECLARED)) {
+ builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement);
+ } else {
+ DeclaredType declaredReturnType = (DeclaredType) returnType;
+ // TODO(gak): should we allow "covariant return" for set values?
+ if (!declaredReturnType.asElement().equals(getSetElement())) {
+ builder.addError(PROVIDES_METHOD_SET_VALUES_RETURN_SET, providesMethodElement);
+ } else if (declaredReturnType.getTypeArguments().isEmpty()) {
+ builder.addError(
+ formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET), providesMethodElement);
+ } else {
+ validateKeyType(builder,
+ Iterables.getOnlyElement(declaredReturnType.getTypeArguments()));
+ }
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ return builder.build();
+ }
+
+ /** Validates that a Provides or Produces method doesn't have multiple qualifiers. */
+ static void validateMethodQualifiers(ValidationReport.Builder<ExecutableElement> builder,
+ ExecutableElement methodElement) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(methodElement);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ builder.addError(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS, methodElement, qualifier);
+ }
+ }
+ }
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, Provides.class.getSimpleName());
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, Provides.class.getSimpleName(), Module.class.getSimpleName());
+ }
+
+ private void validateKeyType(ValidationReport.Builder<? extends Element> reportBuilder,
+ TypeMirror type) {
+ TypeKind kind = type.getKind();
+ if (!(kind.isPrimitive() || kind.equals(DECLARED) || kind.equals(ARRAY))) {
+ reportBuilder.addError(PROVIDES_METHOD_RETURN_TYPE, reportBuilder.getSubject());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java b/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java
new file mode 100644
index 0000000..b2ac74f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ProvisionBinding.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import dagger.Provides;
+import javax.inject.Inject;
+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;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+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 dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.Scope.scopeOf;
+import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
+import static javax.lang.model.element.ElementKind.FIELD;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be provided. New instances
+ * should be created using an instance of the {@link Factory}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ProvisionBinding extends ContributionBinding {
+
+ @Override
+ Binding.Type bindingType() {
+ return Binding.Type.PROVISION;
+ }
+
+ @Override
+ abstract Scope scope();
+
+ static final class Factory {
+ private final Elements elements;
+ private final Types types;
+ private final Key.Factory keyFactory;
+ private final DependencyRequest.Factory dependencyRequestFactory;
+
+ Factory(Elements elements, Types types, Key.Factory keyFactory,
+ DependencyRequest.Factory dependencyRequestFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ /** Returns an unresolved version of this binding. */
+ ProvisionBinding unresolve(ProvisionBinding binding) {
+ checkState(binding.hasNonDefaultTypeParameters());
+ return forInjectConstructor((ExecutableElement) binding.bindingElement(),
+ Optional.<TypeMirror>absent());
+ }
+
+ /**
+ * Returns a ProvisionBinding for the given element. If {@code resolvedType} is present, this
+ * will return a resolved binding, with the key & type resolved to the given type (using
+ * {@link Types#asMemberOf(DeclaredType, Element)}).
+ */
+ ProvisionBinding forInjectConstructor(ExecutableElement constructorElement,
+ Optional<TypeMirror> resolvedType) {
+ checkNotNull(constructorElement);
+ checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
+ checkArgument(isAnnotationPresent(constructorElement, Inject.class));
+ checkArgument(!getQualifier(constructorElement).isPresent());
+
+ ExecutableType cxtorType = MoreTypes.asExecutable(constructorElement.asType());
+ DeclaredType enclosingCxtorType =
+ MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ // If the class this is constructing has some type arguments, resolve everything.
+ if (!enclosingCxtorType.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(enclosingCxtorType)),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(resolved), types.erasure(enclosingCxtorType));
+ cxtorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
+ enclosingCxtorType = resolved;
+ }
+
+ Key key = keyFactory.forInjectConstructorWithResolvedType(enclosingCxtorType);
+ checkArgument(!key.qualifier().isPresent());
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(enclosingCxtorType,
+ constructorElement.getParameters(),
+ cxtorType.getParameterTypes());
+ Optional<DependencyRequest> membersInjectionRequest =
+ membersInjectionRequest(enclosingCxtorType);
+ Scope scope = Scope.scopeOf(constructorElement.getEnclosingElement());
+
+ TypeElement bindingTypeElement =
+ MoreElements.asType(constructorElement.getEnclosingElement());
+
+ return new AutoValue_ProvisionBinding(
+ key,
+ constructorElement,
+ dependencies,
+ findBindingPackage(key),
+ hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types),
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ membersInjectionRequest,
+ Kind.INJECTION,
+ Provides.Type.UNIQUE,
+ scope);
+ }
+
+ private static final ImmutableSet<ElementKind> MEMBER_KINDS =
+ Sets.immutableEnumSet(METHOD, FIELD);
+
+ private Optional<DependencyRequest> membersInjectionRequest(DeclaredType type) {
+ TypeElement typeElement = MoreElements.asType(type.asElement());
+ if (!types.isSameType(elements.getTypeElement(Object.class.getCanonicalName()).asType(),
+ typeElement.getSuperclass())) {
+ return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
+ }
+ for (Element enclosedElement : typeElement.getEnclosedElements()) {
+ if (MEMBER_KINDS.contains(enclosedElement.getKind())
+ && (isAnnotationPresent(enclosedElement, Inject.class))) {
+ return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
+ }
+ }
+ return Optional.absent();
+ }
+
+ ProvisionBinding forProvidesMethod(ExecutableElement providesMethod, TypeMirror contributedBy) {
+ checkNotNull(providesMethod);
+ checkArgument(providesMethod.getKind().equals(METHOD));
+ checkArgument(contributedBy.getKind().equals(TypeKind.DECLARED));
+ Provides providesAnnotation = providesMethod.getAnnotation(Provides.class);
+ checkArgument(providesAnnotation != null);
+ DeclaredType declaredContainer = MoreTypes.asDeclared(contributedBy);
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(types.asMemberOf(declaredContainer, providesMethod));
+ Key key = keyFactory.forProvidesMethod(resolvedMethod, providesMethod);
+ ImmutableSet<DependencyRequest> dependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ declaredContainer,
+ providesMethod.getParameters(),
+ resolvedMethod.getParameterTypes());
+ Scope scope = Scope.scopeOf(providesMethod);
+ return new AutoValue_ProvisionBinding(
+ key,
+ providesMethod,
+ dependencies,
+ findBindingPackage(key),
+ false /* no non-default parameter types */,
+ ConfigurationAnnotations.getNullableType(providesMethod),
+ Optional.of(MoreTypes.asTypeElement(declaredContainer)),
+ Optional.<DependencyRequest>absent(),
+ Kind.PROVISION,
+ providesAnnotation.type(),
+ scope);
+ }
+
+ ProvisionBinding implicitMapOfProviderBinding(DependencyRequest mapOfValueRequest) {
+ checkNotNull(mapOfValueRequest);
+ Optional<Key> implicitMapOfProviderKey =
+ keyFactory.implicitMapProviderKeyFrom(mapOfValueRequest.key());
+ checkArgument(
+ implicitMapOfProviderKey.isPresent(),
+ "%s is not a request for Map<K, V>",
+ mapOfValueRequest);
+ DependencyRequest implicitMapOfProviderRequest =
+ dependencyRequestFactory.forImplicitMapBinding(
+ mapOfValueRequest, implicitMapOfProviderKey.get());
+ return new AutoValue_ProvisionBinding(
+ mapOfValueRequest.key(),
+ implicitMapOfProviderRequest.requestElement(),
+ ImmutableSet.of(implicitMapOfProviderRequest),
+ findBindingPackage(mapOfValueRequest.key()),
+ false /* no non-default parameter types */,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Optional.<DependencyRequest>absent(),
+ Kind.SYNTHETIC,
+ Provides.Type.MAP,
+ scopeOf(implicitMapOfProviderRequest.requestElement()));
+ }
+
+ ProvisionBinding forComponent(TypeElement componentDefinitionType) {
+ checkNotNull(componentDefinitionType);
+ return new AutoValue_ProvisionBinding(
+ keyFactory.forComponent(componentDefinitionType.asType()),
+ componentDefinitionType,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false /* no non-default parameter types */,
+ Optional.<DeclaredType>absent(),
+ Optional.<TypeElement>absent(),
+ Optional.<DependencyRequest>absent(),
+ Kind.COMPONENT,
+ Provides.Type.UNIQUE,
+ Scope.unscoped());
+ }
+
+ ProvisionBinding forComponentMethod(ExecutableElement componentMethod) {
+ checkNotNull(componentMethod);
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ checkArgument(componentMethod.getParameters().isEmpty());
+ Scope scope = Scope.scopeOf(componentMethod);
+ return new AutoValue_ProvisionBinding(
+ keyFactory.forComponentMethod(componentMethod),
+ componentMethod,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false /* no non-default parameter types */,
+ ConfigurationAnnotations.getNullableType(componentMethod),
+ Optional.<TypeElement>absent(),
+ Optional.<DependencyRequest>absent(),
+ Kind.COMPONENT_PROVISION,
+ Provides.Type.UNIQUE,
+ scope);
+ }
+
+ ProvisionBinding forSubcomponentBuilderMethod(
+ ExecutableElement subcomponentBuilderMethod, TypeElement contributedBy) {
+ checkNotNull(subcomponentBuilderMethod);
+ checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD));
+ checkArgument(subcomponentBuilderMethod.getParameters().isEmpty());
+ DeclaredType declaredContainer = asDeclared(contributedBy.asType());
+ return new AutoValue_ProvisionBinding(
+ keyFactory.forSubcomponentBuilderMethod(subcomponentBuilderMethod, declaredContainer),
+ subcomponentBuilderMethod,
+ ImmutableSet.<DependencyRequest>of(),
+ Optional.<String>absent(),
+ false /* no non-default parameter types */,
+ Optional.<DeclaredType>absent(),
+ Optional.of(contributedBy),
+ Optional.<DependencyRequest>absent(),
+ Kind.SUBCOMPONENT_BUILDER,
+ Provides.Type.UNIQUE,
+ Scope.unscoped());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java b/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java
new file mode 100644
index 0000000..024097e
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ResolvedBindings.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.Optional;
+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.Multimap;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
+
+/**
+ * The collection of bindings that have been resolved for a binding key.
+ *
+ * @author Gregory Kick
+ */
+@AutoValue
+abstract class ResolvedBindings {
+ /**
+ * The binding key for which the {@link #bindings()} have been resolved.
+ */
+ abstract BindingKey bindingKey();
+
+ /**
+ * The component in which the bindings in {@link #ownedBindings()},
+ * {@link #ownedContributionBindings()}, and {@link #ownedMembersInjectionBinding()} were
+ * resolved.
+ */
+ abstract ComponentDescriptor owningComponent();
+
+ /**
+ * The contribution bindings for {@link #bindingKey()} that were resolved in
+ * {@link #owningComponent()} or its ancestor components, keyed by the component in which the
+ * binding was resolved. If {@link #bindingKey()}'s kind is not
+ * {@link BindingKey.Kind#CONTRIBUTION}, this is empty.
+ */
+ abstract ImmutableSetMultimap<ComponentDescriptor, ContributionBinding> allContributionBindings();
+
+ /**
+ * The members-injection bindings for {@link #bindingKey()} that were resolved in
+ * {@link #owningComponent()} or its ancestor components, keyed by the component in which the
+ * binding was resolved. If {@link #bindingKey()}'s kind is not
+ * {@link BindingKey.Kind#MEMBERS_INJECTION}, this is empty.
+ */
+ abstract ImmutableMap<ComponentDescriptor, MembersInjectionBinding> allMembersInjectionBindings();
+
+ /**
+ * All bindings for {@link #bindingKey()}, regardless of in which component they were resolved.
+ */
+ ImmutableSet<? extends Binding> bindings() {
+ switch (bindingKey().kind()) {
+ case CONTRIBUTION:
+ return contributionBindings();
+
+ case MEMBERS_INJECTION:
+ return ImmutableSet.copyOf(membersInjectionBinding().asSet());
+
+ default:
+ throw new AssertionError(bindingKey());
+ }
+ }
+
+ /**
+ * All bindings for {@link #bindingKey()} that were resolved in {@link #owningComponent()}.
+ */
+ ImmutableSet<? extends Binding> ownedBindings() {
+ switch (bindingKey().kind()) {
+ case CONTRIBUTION:
+ return ownedContributionBindings();
+
+ case MEMBERS_INJECTION:
+ return ImmutableSet.copyOf(ownedMembersInjectionBinding().asSet());
+
+ default:
+ throw new AssertionError(bindingKey());
+ }
+ }
+
+ /**
+ * All contribution bindings, regardless of owning component.
+ *
+ * @throws IllegalStateException if {@link #bindingKey()} is not a
+ * {@link BindingKey.Kind#CONTRIBUTION}.
+ */
+ ImmutableSet<ContributionBinding> contributionBindings() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
+ return ImmutableSet.copyOf(allContributionBindings().values());
+ }
+
+ /**
+ * The contribution bindings that were resolved in {@link #owningComponent()}.
+ *
+ * @throws IllegalStateException if {@link #bindingKey()} is not a
+ * {@link BindingKey.Kind#CONTRIBUTION}.
+ */
+ ImmutableSet<ContributionBinding> ownedContributionBindings() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
+ return allContributionBindings().get(owningComponent());
+ }
+
+ /**
+ * The members-injection binding, regardless of owning component.
+ *
+ * @throws IllegalStateException if {@link #bindingKey()} is not a
+ * {@link BindingKey.Kind#MEMBERS_INJECTION}.
+ */
+ Optional<MembersInjectionBinding> membersInjectionBinding() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
+ ImmutableSet<MembersInjectionBinding> membersInjectionBindings =
+ FluentIterable.from(allMembersInjectionBindings().values()).toSet();
+ return membersInjectionBindings.isEmpty()
+ ? Optional.<MembersInjectionBinding>absent()
+ : Optional.of(Iterables.getOnlyElement(membersInjectionBindings));
+ }
+
+ /**
+ * The members-injection binding that was resolved in {@link #owningComponent()}.
+ *
+ * @throws IllegalStateException if {@link #bindingKey()} is not a
+ * {@link BindingKey.Kind#MEMBERS_INJECTION}.
+ */
+ Optional<MembersInjectionBinding> ownedMembersInjectionBinding() {
+ checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
+ return Optional.fromNullable(allMembersInjectionBindings().get(owningComponent()));
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} for contribution bindings.
+ */
+ static ResolvedBindings forContributionBindings(
+ BindingKey bindingKey,
+ ComponentDescriptor owningComponent,
+ Multimap<ComponentDescriptor, ? extends ContributionBinding> contributionBindings) {
+ checkArgument(bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION));
+ return new AutoValue_ResolvedBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>copyOf(contributionBindings),
+ ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of());
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} for contribution bindings.
+ */
+ static ResolvedBindings forContributionBindings(
+ BindingKey bindingKey,
+ ComponentDescriptor owningComponent,
+ ContributionBinding... ownedContributionBindings) {
+ return forContributionBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder()
+ .putAll(owningComponent, ownedContributionBindings)
+ .build());
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} for members injection bindings.
+ */
+ static ResolvedBindings forMembersInjectionBinding(
+ BindingKey bindingKey,
+ ComponentDescriptor owningComponent,
+ MembersInjectionBinding ownedMembersInjectionBinding) {
+ checkArgument(bindingKey.kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
+ return new AutoValue_ResolvedBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(),
+ ImmutableMap.of(owningComponent, ownedMembersInjectionBinding));
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
+ */
+ static ResolvedBindings noBindings(BindingKey bindingKey, ComponentDescriptor owningComponent) {
+ return new AutoValue_ResolvedBindings(
+ bindingKey,
+ owningComponent,
+ ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(),
+ ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of());
+ }
+
+ /**
+ * Returns a {@code ResolvedBindings} with the same {@link #bindingKey()} and {@link #bindings()}
+ * as this one, but no {@link #ownedBindings()}.
+ */
+ ResolvedBindings asInheritedIn(ComponentDescriptor owningComponent) {
+ return new AutoValue_ResolvedBindings(
+ bindingKey(), owningComponent, allContributionBindings(), allMembersInjectionBindings());
+ }
+
+ /**
+ * {@code true} if this is a multibindings contribution.
+ */
+ boolean isMultibindings() {
+ return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
+ && !contributionBindings().isEmpty()
+ && contributionTypeFor(contributionBindings()).isMultibinding();
+ }
+
+ /**
+ * {@code true} if this is a unique contribution binding.
+ */
+ boolean isUniqueContribution() {
+ return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
+ && !contributionBindings().isEmpty()
+ && !contributionTypeFor(contributionBindings()).isMultibinding();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Scope.java b/compiler/src/main/java/dagger/internal/codegen/Scope.java
new file mode 100644
index 0000000..bcb009d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Scope.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.AnnotationMirrors;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nullable;
+import javax.inject.Singleton;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.auto.common.MoreTypes.isTypeOf;
+import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
+import static dagger.internal.codegen.InjectionAnnotations.getScopeAnnotation;
+
+/**
+ * A representation of the scope (or lack of it) associated with a component, providing method
+ * or injection location.
+ */
+final class Scope {
+
+ /**
+ * An internal representation for an unscoped binding.
+ */
+ private static final Scope UNSCOPED = new Scope();
+
+ /**
+ * The underlying {@link AnnotationMirror} that represents the scope annotation.
+ */
+ @Nullable
+ private final AnnotationMirror annotationMirror;
+
+ private Scope(@Nullable AnnotationMirror annotationMirror) {
+ this.annotationMirror = annotationMirror;
+ }
+
+ private Scope() {
+ this(null);
+ }
+
+ /**
+ * Returns representation for an unscoped binding.
+ */
+ static Scope unscoped() {
+ return UNSCOPED;
+ }
+
+ /**
+ * If the source code element has an associated scoped annotation then returns a representation
+ * of that scope, otherwise returns a representation for an unscoped binding.
+ */
+ static Scope scopeOf(Element element) {
+ Optional<AnnotationMirror> scopeAnnotation = getScopeAnnotation(element);
+ return scopeAnnotation.isPresent() ? new Scope(scopeAnnotation.get()) : UNSCOPED;
+ }
+
+ /**
+ * Returns true if the scope is present, i.e. it's not unscoped binding.
+ */
+ public boolean isPresent() {
+ return annotationMirror != null;
+ }
+
+ /**
+ * Returns true if the scope represents the {@link Singleton @Singleton} annotation.
+ */
+ public boolean isSingleton() {
+ return annotationMirror != null
+ && isTypeOf(Singleton.class, annotationMirror.getAnnotationType());
+ }
+
+ /**
+ * Returns the readable source representation (name with @ prefix) of the 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}.
+ *
+ * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will
+ * throw an {@link IllegalStateException} otherwise. This does not return any annotation values
+ * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them.
+ */
+ public String getReadableSource() {
+ return stripCommonTypePrefixes("@" + getQualifiedName());
+ }
+
+ /**
+ * Returns the fully qualified name of the annotation type.
+ *
+ * <p>Make sure that the scope is actually {@link #isPresent() present} before calling as it will
+ * throw an {@link IllegalStateException} otherwise. This does not return any annotation values
+ * as according to {@link javax.inject.Scope} scope annotations are not supposed to use them.
+ */
+ public String getQualifiedName() {
+ Preconditions.checkState(annotationMirror != null,
+ "Cannot create a stripped source representation of no annotation");
+ TypeElement typeElement = MoreTypes.asTypeElement(annotationMirror.getAnnotationType());
+ return typeElement.getQualifiedName().toString();
+ }
+
+ /**
+ * Scopes are equal if the underlying {@link AnnotationMirror} are equivalent according to
+ * {@link AnnotationMirrors#equivalence()}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj instanceof Scope) {
+ Scope that = (Scope) obj;
+ return AnnotationMirrors.equivalence()
+ .equivalent(this.annotationMirror, that.annotationMirror);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return AnnotationMirrors.equivalence().hash(annotationMirror);
+ }
+
+ /**
+ * Returns a debug representation of the scope.
+ */
+ @Override
+ public String toString() {
+ return annotationMirror == null ? "UNSCOPED" : annotationMirror.toString();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java
new file mode 100644
index 0000000..c262098
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerationException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+/**
+ * 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.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+final class SourceFileGenerationException extends Exception {
+ private final ImmutableSet<ClassName> generatedClassNames;
+ private final Optional<? extends Element> associatedElement;
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause,
+ Optional<? extends Element> associatedElement) {
+ super(createMessage(generatedClassNames, cause.getMessage()), cause);
+ this.generatedClassNames = ImmutableSet.copyOf(generatedClassNames);
+ this.associatedElement = checkNotNull(associatedElement);
+ }
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause) {
+ this(generatedClassNames, cause, Optional.<Element>absent());
+ }
+
+ SourceFileGenerationException(Iterable<ClassName> generatedClassNames, Throwable cause,
+ Element associatedElement) {
+ this(generatedClassNames, cause, Optional.of(associatedElement));
+ }
+
+ public ImmutableSet<ClassName> generatedClassNames() {
+ return generatedClassNames;
+ }
+
+ public Optional<? extends Element> associatedElement() {
+ return associatedElement;
+ }
+
+ private static String createMessage(Iterable<ClassName> generatedClassNames, String message) {
+ return String.format("Could not generate %s: %s.",
+ Iterables.isEmpty(generatedClassNames)
+ ? "unknown files"
+ : Iterables.toString(generatedClassNames),
+ message);
+ }
+
+ void printMessageTo(Messager messager) {
+ if (associatedElement.isPresent()) {
+ messager.printMessage(ERROR, getMessage(), associatedElement.get());
+ } else {
+ messager.printMessage(ERROR, getMessage());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java
new file mode 100644
index 0000000..4b6efc0
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFileGenerator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.JavaWriter;
+import dagger.internal.codegen.writer.TypeWriter;
+import java.io.IOException;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * 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.
+ * @author Gregory Kick
+ * @since 2.0
+ */
+abstract class SourceFileGenerator<T> {
+ private final Filer filer;
+
+ SourceFileGenerator(Filer filer) {
+ this.filer = checkNotNull(filer);
+ }
+
+ final void generate(T input) throws SourceFileGenerationException {
+ ClassName generatedTypeName = nameGeneratedType(input);
+ ImmutableSet<Element> originatingElements =
+ ImmutableSet.<Element>copyOf(getOriginatingElements(input));
+ try {
+ ImmutableSet<JavaWriter> writers = write(generatedTypeName, input);
+ for (JavaWriter javaWriter : writers) {
+ try {
+ javaWriter.file(filer, originatingElements);
+ } catch (IOException e) {
+ throw new SourceFileGenerationException(getNamesForWriters(javaWriter.getTypeWriters()),
+ e, getElementForErrorReporting(input));
+ }
+ }
+ } 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(ImmutableList.<ClassName>of(), e,
+ getElementForErrorReporting(input));
+ }
+ }
+
+ private static Iterable<ClassName> getNamesForWriters(Iterable<TypeWriter> typeWriters) {
+ return Iterables.transform(typeWriters, new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name();
+ }
+ });
+ }
+
+ /**
+ * Implementations should return the {@link ClassName} for the top-level type to be generated.
+ */
+ abstract ClassName nameGeneratedType(T input);
+
+ /**
+ * Implementations should return {@link Element} instances from which the source is to be
+ * generated.
+ */
+ abstract Iterable<? extends Element> getOriginatingElements(T input);
+
+ /**
+ * Returns an optional element to be used for reporting errors. This returns a single element
+ * rather than a collection to reduce output noise.
+ */
+ abstract Optional<? extends Element> getElementForErrorReporting(T input);
+
+ /**
+ */
+ abstract ImmutableSet<JavaWriter> write(ClassName generatedTypeName, T input);
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java
new file mode 100644
index 0000000..7ad0acb
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.CaseFormat;
+import com.google.common.collect.ComparisonChain;
+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.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Ordering;
+import dagger.internal.DoubleCheckLazy;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Utilities for generating files.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+class SourceFiles {
+ /**
+ * Sorts {@link DependencyRequest} instances in an order likely to reflect their logical
+ * importance.
+ */
+ static final Ordering<DependencyRequest> DEPENDENCY_ORDERING = new Ordering<DependencyRequest>() {
+ @Override
+ public int compare(DependencyRequest left, DependencyRequest right) {
+ return ComparisonChain.start()
+ // put fields before parameters
+ .compare(left.requestElement().getKind(), right.requestElement().getKind())
+ // order by dependency kind
+ .compare(left.kind(), right.kind())
+ // then sort by name
+ .compare(left.requestElement().getSimpleName().toString(),
+ right.requestElement().getSimpleName().toString()).result();
+ }
+ };
+
+ /**
+ * A variant of {@link #indexDependenciesByKey} that maps from unresolved keys
+ * to requests. This is used when generating component's initialize()
+ * methods (and in members injectors) in order to instantiate dependent
+ * providers. Consider a generic type of {@code Foo<T>} with a constructor
+ * of {@code Foo(T t, T t1, A a, A a1)}. That will be collapsed to a factory
+ * taking a {@code Provider<T> tProvider, Provider<A> aProvider}. However,
+ * if it was referenced as {@code Foo<A>}, we need to make sure we still
+ * pass two providers. Naively (if we just referenced by resolved BindingKey),
+ * we would have passed a single {@code aProvider}.
+ */
+ // TODO(user): Refactor these indexing methods so that the binding itself knows what sort of
+ // binding keys and framework classes that it needs.
+ static ImmutableSetMultimap<BindingKey, DependencyRequest> indexDependenciesByUnresolvedKey(
+ Types types, Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap.Builder<BindingKey, DependencyRequest> dependenciesByKeyBuilder =
+ new ImmutableSetMultimap.Builder<BindingKey, DependencyRequest>()
+ .orderValuesBy(DEPENDENCY_ORDERING);
+ for (DependencyRequest dependency : dependencies) {
+ BindingKey resolved = dependency.bindingKey();
+ // To get the proper unresolved type, we have to extract the proper type from the
+ // request type again (because we're looking at the actual element's type).
+ TypeMirror unresolvedType =
+ DependencyRequest.Factory.extractKindAndType(dependency.requestElement().asType()).type();
+ BindingKey unresolved =
+ BindingKey.create(resolved.kind(), resolved.key().withType(types, unresolvedType));
+ dependenciesByKeyBuilder.put(unresolved, dependency);
+ }
+ return dependenciesByKeyBuilder.build();
+ }
+
+ /**
+ * Allows dependency requests to be grouped by the key they're requesting.
+ * This is used by factory generation in order to minimize the number of parameters
+ * required in the case where a given key is requested more than once. This expects
+ * unresolved dependency requests, otherwise we may generate factories based on
+ * a particular usage of a class as opposed to the generic types of the class.
+ */
+ static ImmutableSetMultimap<BindingKey, DependencyRequest> indexDependenciesByKey(
+ Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap.Builder<BindingKey, DependencyRequest> dependenciesByKeyBuilder =
+ new ImmutableSetMultimap.Builder<BindingKey, DependencyRequest>()
+ .orderValuesBy(DEPENDENCY_ORDERING);
+ for (DependencyRequest dependency : dependencies) {
+ dependenciesByKeyBuilder.put(dependency.bindingKey(), dependency);
+ }
+ return dependenciesByKeyBuilder.build();
+ }
+
+ /**
+ * This method generates names and keys for the framework classes necessary for all of the
+ * bindings. It is responsible for the following:
+ * <ul>
+ * <li>Choosing a name that associates the binding with all of the dependency requests for this
+ * type.
+ * <li>Choosing a name that is <i>probably</i> associated with the type being bound.
+ * <li>Ensuring that no two bindings end up with the same name.
+ * </ul>
+ *
+ * @return Returns the mapping from {@link BindingKey} to field, sorted by the name of the field.
+ */
+ static ImmutableMap<BindingKey, FrameworkField> generateBindingFieldsForDependencies(
+ DependencyRequestMapper dependencyRequestMapper,
+ Iterable<? extends DependencyRequest> dependencies) {
+ ImmutableSetMultimap<BindingKey, DependencyRequest> dependenciesByKey =
+ indexDependenciesByKey(dependencies);
+ Map<BindingKey, Collection<DependencyRequest>> dependenciesByKeyMap =
+ dependenciesByKey.asMap();
+ ImmutableMap.Builder<BindingKey, FrameworkField> bindingFields = ImmutableMap.builder();
+ for (Entry<BindingKey, Collection<DependencyRequest>> entry
+ : dependenciesByKeyMap.entrySet()) {
+ BindingKey bindingKey = entry.getKey();
+ Collection<DependencyRequest> requests = entry.getValue();
+ Class<?> frameworkClass =
+ dependencyRequestMapper.getFrameworkClass(requests.iterator().next());
+ // collect together all of the names that we would want to call the provider
+ ImmutableSet<String> dependencyNames =
+ FluentIterable.from(requests).transform(new DependencyVariableNamer()).toSet();
+
+ if (dependencyNames.size() == 1) {
+ // if there's only one name, great! use it!
+ String name = Iterables.getOnlyElement(dependencyNames);
+ bindingFields.put(bindingKey,
+ FrameworkField.createWithTypeFromKey(frameworkClass, bindingKey, name));
+ } 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()));
+ }
+ bindingFields.put(bindingKey, FrameworkField.createWithTypeFromKey(
+ frameworkClass, bindingKey, compositeNameBuilder.toString()));
+ }
+ }
+ return bindingFields.build();
+ }
+
+ static Snippet frameworkTypeUsageStatement(Snippet frameworkTypeMemberSelect,
+ DependencyRequest.Kind dependencyKind) {
+ switch (dependencyKind) {
+ case LAZY:
+ return Snippet.format("%s.create(%s)", ClassName.fromClass(DoubleCheckLazy.class),
+ frameworkTypeMemberSelect);
+ case INSTANCE:
+ case FUTURE:
+ return Snippet.format("%s.get()", frameworkTypeMemberSelect);
+ case PROVIDER:
+ case PRODUCER:
+ case MEMBERS_INJECTOR:
+ return Snippet.format("%s", frameworkTypeMemberSelect);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * 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;
+ checkArgument(!contribution.isSyntheticBinding());
+ ClassName enclosingClassName = ClassName.fromTypeElement(contribution.bindingTypeElement());
+ switch (contribution.bindingKind()) {
+ case INJECTION:
+ case PROVISION:
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return enclosingClassName
+ .topLevelClassName()
+ .peerNamed(
+ enclosingClassName.classFileName()
+ + "_"
+ + factoryPrefix(contribution)
+ + "Factory");
+
+ default:
+ throw new AssertionError();
+ }
+
+ case MEMBERS_INJECTION:
+ return membersInjectorNameForType(binding.bindingTypeElement());
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns the generated factory or members injector name parameterized with the proper type
+ * parameters if necessary.
+ */
+ static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) {
+ return generatedClassNameForBinding(binding).withTypeParameters(bindingTypeParameters(binding));
+ }
+
+ private static ImmutableList<TypeName> bindingTypeParameters(Binding binding)
+ throws AssertionError {
+ TypeMirror bindingType;
+ switch (binding.bindingType()) {
+ case PROVISION:
+ case PRODUCTION:
+ ContributionBinding contributionBinding = (ContributionBinding) binding;
+ if (contributionBinding.contributionType().isMultibinding()) {
+ return ImmutableList.of();
+ }
+ switch (contributionBinding.bindingKind()) {
+ case INJECTION:
+ bindingType = contributionBinding.key().type();
+ break;
+
+ case PROVISION:
+ // For provision bindings, we parameterize creation on the types of
+ // the module, not the types of the binding.
+ // Consider: Module<A, B, C> { @Provides List<B> provideB(B b) { .. }}
+ // The binding is just parameterized on <B>, but we need all of <A, B, C>.
+ bindingType = contributionBinding.bindingTypeElement().asType();
+ break;
+
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ // TODO(beder): Can these be treated just like PROVISION?
+ throw new UnsupportedOperationException();
+
+ default:
+ return ImmutableList.of();
+ }
+ break;
+
+ case MEMBERS_INJECTION:
+ bindingType = binding.key().type();
+ break;
+
+ default:
+ throw new AssertionError();
+ }
+ TypeName bindingTypeName = TypeNames.forTypeMirror(bindingType);
+ return bindingTypeName instanceof ParameterizedTypeName
+ ? ((ParameterizedTypeName) bindingTypeName).parameters()
+ : ImmutableList.<TypeName>of();
+ }
+
+ static ClassName membersInjectorNameForType(TypeElement typeElement) {
+ ClassName injectedClassName = ClassName.fromTypeElement(typeElement);
+ return injectedClassName
+ .topLevelClassName()
+ .peerNamed(injectedClassName.classFileName() + "_MembersInjector");
+ }
+
+ static ClassName generatedMonitoringModuleName(TypeElement componentElement) {
+ ClassName componentName = ClassName.fromTypeElement(componentElement);
+ return componentName
+ .topLevelClassName()
+ .peerNamed(componentName.classFileName() + "_MonitoringModule");
+ }
+
+ private static String factoryPrefix(ContributionBinding binding) {
+ switch (binding.bindingKind()) {
+ case INJECTION:
+ return "";
+
+ case PROVISION:
+ case IMMEDIATE:
+ case FUTURE_PRODUCTION:
+ return CaseFormat.LOWER_CAMEL.to(
+ UPPER_CAMEL, ((ExecutableElement) binding.bindingElement()).getSimpleName().toString());
+
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private SourceFiles() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
new file mode 100644
index 0000000..1287668
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/SubcomponentWriter.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import dagger.internal.codegen.ComponentDescriptor.BuilderSpec;
+import dagger.internal.codegen.ComponentGenerator.MemberSelect;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ClassWriter;
+import dagger.internal.codegen.writer.FieldWriter;
+import dagger.internal.codegen.writer.MethodWriter;
+import dagger.internal.codegen.writer.Snippet;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Sets.difference;
+import static dagger.internal.codegen.AbstractComponentWriter.InitializationState.UNINITIALIZED;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+/**
+ * Creates the nested implementation class for a subcomponent.
+ */
+class SubcomponentWriter extends AbstractComponentWriter {
+
+ private AbstractComponentWriter parent;
+ private ExecutableElement subcomponentFactoryMethod;
+
+ public SubcomponentWriter(
+ AbstractComponentWriter parent,
+ ExecutableElement subcomponentFactoryMethod,
+ BindingGraph subgraph) {
+ super(
+ parent.types,
+ parent.elements,
+ parent.keyFactory,
+ parent.nullableValidationType,
+ parent.name.nestedClassNamed(subcomponentSimpleName(subgraph)),
+ subgraph);
+ this.parent = parent;
+ this.subcomponentFactoryMethod = subcomponentFactoryMethod;
+ }
+
+ private static String subcomponentSimpleName(BindingGraph subgraph) {
+ return subgraph.componentDescriptor().componentDefinitionType().getSimpleName() + "Impl";
+ }
+
+ @Override
+ protected InitializationState getInitializationState(BindingKey bindingKey) {
+ InitializationState initializationState = super.getInitializationState(bindingKey);
+ return initializationState.equals(UNINITIALIZED)
+ ? parent.getInitializationState(bindingKey)
+ : initializationState;
+ }
+
+ @Override
+ protected Optional<Snippet> getOrCreateComponentContributionFieldSnippet(
+ TypeElement contributionType) {
+ return super.getOrCreateComponentContributionFieldSnippet(contributionType)
+ .or(parent.getOrCreateComponentContributionFieldSnippet(contributionType));
+ }
+
+ @Override
+ protected MemberSelect getMemberSelect(BindingKey key) {
+ MemberSelect memberSelect = super.getMemberSelect(key);
+ return memberSelect == null ? parent.getMemberSelect(key) : memberSelect;
+ }
+
+ @Override
+ protected Optional<MemberSelect> getMultibindingContributionSnippet(ContributionBinding binding) {
+ return super.getMultibindingContributionSnippet(binding)
+ .or(parent.getMultibindingContributionSnippet(binding));
+ }
+
+ private ExecutableType resolvedSubcomponentFactoryMethod() {
+ return MoreTypes.asExecutable(
+ types.asMemberOf(
+ MoreTypes.asDeclared(parent.componentDefinitionType().asType()),
+ subcomponentFactoryMethod));
+ }
+
+ @Override
+ protected ClassWriter createComponentClass() {
+ ClassWriter componentWriter = parent.componentWriter.addNestedClass(name.simpleName());
+ componentWriter.addModifiers(PRIVATE, FINAL);
+ componentWriter.setSupertype(
+ MoreTypes.asTypeElement(
+ graph.componentDescriptor().builderSpec().isPresent()
+ ? graph
+ .componentDescriptor()
+ .builderSpec()
+ .get()
+ .componentType()
+ : resolvedSubcomponentFactoryMethod().getReturnType()));
+ return componentWriter;
+ }
+
+ @Override
+ protected void addBuilder() {
+ // Only write subcomponent builders if there is a spec.
+ if (graph.componentDescriptor().builderSpec().isPresent()) {
+ super.addBuilder();
+ }
+ }
+
+ @Override
+ protected ClassWriter createBuilder() {
+ // Only write subcomponent builders if there is a spec.
+ verify(graph.componentDescriptor().builderSpec().isPresent());
+ return parent.componentWriter.addNestedClass(
+ componentDefinitionTypeName().simpleName() + "Builder");
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ MethodWriter componentMethod;
+ if (graph.componentDescriptor().builderSpec().isPresent()) {
+ BuilderSpec spec = graph.componentDescriptor().builderSpec().get();
+ componentMethod =
+ parent.componentWriter.addMethod(
+ spec.builderDefinitionType().asType(),
+ subcomponentFactoryMethod.getSimpleName().toString());
+ componentMethod.body().addSnippet("return new %s();", builderName.get());
+ } else {
+ ExecutableType resolvedMethod = resolvedSubcomponentFactoryMethod();
+ componentMethod =
+ parent.componentWriter.addMethod(
+ resolvedMethod.getReturnType(), subcomponentFactoryMethod.getSimpleName().toString());
+ writeSubcomponentWithoutBuilder(componentMethod, resolvedMethod);
+ }
+ componentMethod.addModifiers(PUBLIC);
+ componentMethod.annotate(Override.class);
+ }
+
+ private void writeSubcomponentWithoutBuilder(
+ MethodWriter componentMethod, ExecutableType resolvedMethod) {
+ ImmutableList.Builder<Snippet> subcomponentConstructorParameters = ImmutableList.builder();
+ List<? extends VariableElement> params = subcomponentFactoryMethod.getParameters();
+ List<? extends TypeMirror> paramTypes = resolvedMethod.getParameterTypes();
+ for (int i = 0; i < params.size(); i++) {
+ VariableElement moduleVariable = params.get(i);
+ TypeElement moduleTypeElement = MoreTypes.asTypeElement(paramTypes.get(i));
+ TypeName moduleType = TypeNames.forTypeMirror(paramTypes.get(i));
+ componentMethod.addParameter(moduleType, moduleVariable.getSimpleName().toString());
+ if (!componentContributionFields.containsKey(moduleTypeElement)) {
+ String preferredModuleName =
+ CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, moduleTypeElement.getSimpleName().toString());
+ FieldWriter contributionField =
+ componentWriter.addField(moduleTypeElement, preferredModuleName);
+ contributionField.addModifiers(PRIVATE, FINAL);
+ String actualModuleName = contributionField.name();
+ constructorWriter.addParameter(moduleType, actualModuleName);
+ constructorWriter.body()
+ .addSnippet("if (%s == null) {", actualModuleName)
+ .addSnippet(" throw new NullPointerException();")
+ .addSnippet("}");
+ constructorWriter.body().addSnippet("this.%1$s = %1$s;", actualModuleName);
+ MemberSelect moduleSelect =
+ MemberSelect.instanceSelect(name, Snippet.format(actualModuleName));
+ componentContributionFields.put(moduleTypeElement, moduleSelect);
+ subcomponentConstructorParameters.add(Snippet.format("%s", moduleVariable.getSimpleName()));
+ }
+ }
+
+ Set<TypeElement> uninitializedModules =
+ difference(graph.componentRequirements(), componentContributionFields.keySet());
+
+ for (TypeElement moduleType : uninitializedModules) {
+ String preferredModuleName =
+ CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, moduleType.getSimpleName().toString());
+ FieldWriter contributionField = componentWriter.addField(moduleType, preferredModuleName);
+ contributionField.addModifiers(PRIVATE, FINAL);
+ String actualModuleName = contributionField.name();
+ constructorWriter.body().addSnippet("this.%s = new %s();",
+ actualModuleName, ClassName.fromTypeElement(moduleType));
+ MemberSelect moduleSelect =
+ MemberSelect.instanceSelect(name, Snippet.format(actualModuleName));
+ componentContributionFields.put(moduleType, moduleSelect);
+ }
+
+ componentMethod.body().addSnippet("return new %s(%s);",
+ name, Snippet.makeParametersSnippet(subcomponentConstructorParameters.build()));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/Util.java b/compiler/src/main/java/dagger/internal/codegen/Util.java
new file mode 100644
index 0000000..8c1aba3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/Util.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import dagger.producers.Produced;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Provider;
+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.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+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 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;
+
+/**
+ * Utilities for handling types in annotation processors
+ */
+final class Util {
+ /**
+ * Returns the {@code V} type for a {@link Map} type like {@code Map<K, Provider<V>>} if the map
+ * includes such a construction
+ */
+ public static TypeMirror getProvidedValueTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ return asDeclared(mapType.getTypeArguments().get(1)).getTypeArguments().get(0);
+ }
+
+ // TODO(cgruber): Consider an object that holds and exposes the various parts of a Map type.
+ /**
+ * returns the value type for a {@link Map} type like Map<K, V>}.
+ */
+ public static TypeMirror getValueTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ return mapType.getTypeArguments().get(1);
+ }
+
+ /**
+ * Returns the key type for a {@link Map} type like Map<K, Provider<V>>}
+ */
+ public static TypeMirror getKeyTypeOfMap(DeclaredType mapType) {
+ checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
+ return mapType.getTypeArguments().get(0);
+ }
+
+ /**
+ * Returns true if {@code type} is a {@link Map} whose value type is not a {@link Provider}.
+ */
+ public static boolean isMapWithNonProvidedValues(TypeMirror type) {
+ return MoreTypes.isType(type)
+ && MoreTypes.isTypeOf(Map.class, type)
+ && !MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
+ }
+
+ /**
+ * Returns true if {@code type} is a {@link Map} whose value type is a {@link Provider}.
+ */
+ public static boolean isMapWithProvidedValues(TypeMirror type) {
+ return MoreTypes.isType(type)
+ && MoreTypes.isTypeOf(Map.class, type)
+ && MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
+ }
+
+ /** Returns true if {@code type} is a {@code Set<Produced<T>>}. */
+ static boolean isSetOfProduced(TypeMirror type) {
+ return MoreTypes.isType(type)
+ && MoreTypes.isTypeOf(Set.class, type)
+ && MoreTypes.isTypeOf(Produced.class, MoreTypes.asDeclared(type).getTypeArguments().get(0));
+ }
+
+ /**
+ * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Wrapper} for that type.
+ */
+ static <T> Optional<Equivalence.Wrapper<T>> wrapOptionalInEquivalence(
+ Equivalence<T> equivalence, Optional<T> optional) {
+ return optional.isPresent()
+ ? Optional.of(equivalence.wrap(optional.get()))
+ : Optional.<Equivalence.Wrapper<T>>absent();
+ }
+
+ /**
+ * Unwraps an {@link Optional} of a {@link Wrapper} into an {@code Optional} of the underlying
+ * type.
+ */
+ static <T> Optional<T> unwrapOptionalEquivalence(
+ Optional<Equivalence.Wrapper<T>> wrappedOptional) {
+ return wrappedOptional.isPresent()
+ ? Optional.of(wrappedOptional.get().get())
+ : Optional.<T>absent();
+ }
+
+ 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;
+ default:
+ throw new AssertionError("TypeElement cannot have nesting kind: "
+ + typeElement.getNestingKind());
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ static ImmutableSet<ExecutableElement> getUnimplementedMethods(
+ Elements elements, TypeElement type) {
+ ImmutableSet.Builder<ExecutableElement> unimplementedMethods = ImmutableSet.builder();
+ Set<ExecutableElement> methods = getLocalAndInheritedMethods(type, elements);
+ for (ExecutableElement method : methods) {
+ if (method.getModifiers().contains(Modifier.ABSTRACT)) {
+ unimplementedMethods.add(method);
+ }
+ }
+ return unimplementedMethods.build();
+ }
+
+ private Util() {}
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java b/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java
new file mode 100644
index 0000000..e174067
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ValidationReport.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.util.SimpleElementVisitor6;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.NOTE;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+/**
+ * A collection of items describing contractual issues with the code as presented to an annotation
+ * processor. A "clean" report (i.e. with no issues) is a report with no {@linkplain Item items}
+ * and clean subreports. Callers will typically print the results of the report to a
+ * {@link Messager} instance using {@link #printMessagesTo}.
+ *
+ * <p>A report describes a subject {@link Element}. Callers may choose to add report items about
+ * other elements that are contained within or related to the subject. Since {@link Diagnostic}
+ * reporting is expected to be associated with elements that are currently being compiled,
+ * {@link #printMessagesTo(Messager)} will only associate messages with non-subject elements if they
+ * are contained within the subject. Otherwise, they will be associated with the subject and contain
+ * a reference to the item's element in the message string. It is the responsibility of the caller
+ * to choose subjects that are part of the compilation.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@AutoValue
+abstract class ValidationReport<T extends Element> {
+ abstract T subject();
+ abstract ImmutableSet<Item> items();
+ abstract ImmutableSet<ValidationReport<?>> subreports();
+
+ boolean isClean() {
+ for (Item item : items()) {
+ switch (item.kind()) {
+ case ERROR:
+ return false;
+ default:
+ break;
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ if (!subreport.isClean()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void printMessagesTo(Messager messager) {
+ for (Item item : items()) {
+ if (isEnclosedIn(subject(), item.element())) {
+ if (item.annotation().isPresent()) {
+ 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", elementString(item.element()), item.message());
+ if (item.annotation().isPresent()) {
+ messager.printMessage(item.kind(), message, subject(), item.annotation().get());
+ } else {
+ messager.printMessage(item.kind(), message, subject());
+ }
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ subreport.printMessagesTo(messager);
+ }
+ }
+
+ private static String elementString(Element element) {
+ return element.accept(
+ new SimpleElementVisitor6<String, Void>() {
+ @Override
+ protected String defaultAction(Element e, Void p) {
+ return e.toString();
+ }
+
+ @Override
+ public String visitExecutable(ExecutableElement e, Void p) {
+ return e.getEnclosingElement().accept(this, null) + '.' + e.toString();
+ }
+ },
+ null);
+ }
+
+ 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();
+ }
+
+ static <T extends Element> Builder<T> about(T subject) {
+ return new Builder<T>(subject);
+ }
+
+ 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 Builder(T subject) {
+ this.subject = subject;
+ }
+
+ T getSubject() {
+ return subject;
+ }
+
+ Builder<T> addItems(Iterable<Item> newItems) {
+ items.addAll(newItems);
+ return this;
+ }
+
+ Builder<T> addError(String message) {
+ addItem(message, ERROR, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addError(String message, Element element) {
+ addItem(message, ERROR, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addError(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, ERROR, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addWarning(String message) {
+ addItem(message, WARNING, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addWarning(String message, Element element) {
+ addItem(message, WARNING, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addWarning(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, WARNING, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addNote(String message) {
+ addItem(message, NOTE, subject, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addNote(String message, Element element) {
+ addItem(message, NOTE, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addNote(String message, Element element, AnnotationMirror annotation) {
+ addItem(message, NOTE, element, Optional.of(annotation));
+ return this;
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element) {
+ addItem(message, kind, element, Optional.<AnnotationMirror>absent());
+ return this;
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element, AnnotationMirror annotation) {
+ addItem(message, kind, element, Optional.of(annotation));
+ return this;
+ }
+
+ private Builder<T> addItem(String message, Kind kind, Element element,
+ Optional<AnnotationMirror> annotation) {
+ items.add(new AutoValue_ValidationReport_Item(message, kind, element, annotation));
+ return this;
+ }
+
+ Builder<T> addSubreport(ValidationReport<?> subreport) {
+ subreports.add(subreport);
+ return this;
+ }
+
+ ValidationReport<T> build() {
+ return new AutoValue_ValidationReport<T>(subject, items.build(), subreports.build());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/ValidationType.java b/compiler/src/main/java/dagger/internal/codegen/ValidationType.java
new file mode 100644
index 0000000..d602072
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/ValidationType.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (C) 2015 Google, Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF 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.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.absent();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java
new file mode 100644
index 0000000..8dbf27b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/AnnotationWriter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+
+import static dagger.internal.codegen.writer.Writables.toStringWritable;
+
+public final class AnnotationWriter implements Writable, HasClassReferences {
+ private final ClassName annotationName;
+ private final Set<HasClassReferences> memberReferences = Sets.newLinkedHashSet();
+ private final SortedMap<String, Writable> memberMap = Maps.newTreeMap();
+
+ AnnotationWriter(ClassName annotationName) {
+ this.annotationName = annotationName;
+ }
+
+ public void setValue(String value) {
+ setMember("value", value);
+ }
+
+ public void setMember(String name, int value) {
+ memberMap.put(name, toStringWritable(value));
+ }
+
+ public void setMember(String name, String value) {
+ memberMap.put(name, toStringWritable(StringLiteral.forValue(value)));
+ }
+
+ public <T extends Enum<T>> void setMember(String name, T value) {
+ Snippet snippet = Snippet.format("%s.%s", ClassName.fromClass(value.getClass()), value);
+ memberMap.put(name, snippet);
+ memberReferences.add(snippet);
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append('@');
+ annotationName.write(appendable, context);
+ if (!memberMap.isEmpty()) {
+ appendable.append('(');
+ if (memberMap.size() == 1) {
+ Entry<String, Writable> onlyEntry = Iterables.getOnlyElement(memberMap.entrySet());
+ if (!onlyEntry.getKey().equals("value")) {
+ appendable.append(onlyEntry.getKey()).append(" = ");
+ }
+ onlyEntry.getValue().write(appendable, context);
+ }
+ appendable.append(')');
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(memberReferences)
+ .append(annotationName)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java
new file mode 100644
index 0000000..e796062
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ArrayTypeName.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import java.io.IOException;
+import java.util.Set;
+
+final class ArrayTypeName implements TypeName {
+ private final TypeName componentType;
+
+ ArrayTypeName(TypeName componentType) {
+ this.componentType = componentType;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return componentType.referencedClasses();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return componentType.write(appendable, context).append("[]");
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof ArrayTypeName)
+ && this.componentType.equals(((ArrayTypeName) obj).componentType);
+ }
+
+ @Override
+ public int hashCode() {
+ return componentType.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java
new file mode 100644
index 0000000..c00dd5f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/BlockWriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+public final class BlockWriter implements Writable, HasClassReferences {
+ private final List<Snippet> snippets;
+
+ BlockWriter() {
+ this.snippets = Lists.newArrayList();
+ }
+
+ public BlockWriter addSnippet(String snippet, Object... args) {
+ snippets.add(Snippet.format(snippet, args));
+ return this;
+ }
+
+ public BlockWriter addSnippet(Snippet snippet) {
+ snippets.add(snippet);
+ return this;
+ }
+
+ boolean isEmpty() {
+ return snippets.isEmpty();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ for (Snippet snippet : snippets) {
+ appendable.append('\n');
+ snippet.write(appendable, context);
+ }
+ return appendable.append('\n');
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(snippets)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java
new file mode 100644
index 0000000..bd0791f
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ClassName.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Ascii;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.lang.model.element.NestingKind.MEMBER;
+import static javax.lang.model.element.NestingKind.TOP_LEVEL;
+
+/**
+ * Represents a fully-qualified class name for {@link NestingKind#TOP_LEVEL} and
+ * {@link NestingKind#MEMBER} classes.
+ *
+ * @since 2.0
+ */
+public final class ClassName implements TypeName, Comparable<ClassName> {
+ private String fullyQualifiedName = null;
+ private final String packageName;
+ /* From top to bottom. E.g.: this field will contain ["A", "B"] for pgk.A.B.C */
+ private final ImmutableList<String> enclosingSimpleNames;
+ private final String simpleName;
+
+ private ClassName(String packageName, ImmutableList<String> enclosingSimpleNames,
+ String simpleName) {
+ this.packageName = packageName;
+ this.enclosingSimpleNames = enclosingSimpleNames;
+ this.simpleName = simpleName;
+ }
+
+ public String packageName() {
+ return packageName;
+ }
+
+ public ImmutableList<String> enclosingSimpleNames() {
+ return enclosingSimpleNames;
+ }
+
+ public Optional<ClassName> enclosingClassName() {
+ return enclosingSimpleNames.isEmpty()
+ ? Optional.<ClassName>absent()
+ : Optional.of(new ClassName(packageName,
+ enclosingSimpleNames.subList(0, enclosingSimpleNames.size() - 1),
+ enclosingSimpleNames.get(enclosingSimpleNames.size() - 1)));
+ }
+
+ public String simpleName() {
+ return simpleName;
+ }
+
+ public String canonicalName() {
+ if (fullyQualifiedName == null) {
+ StringBuilder builder = new StringBuilder(packageName());
+ if (builder.length() > 0) {
+ builder.append('.');
+ }
+ for (String enclosingSimpleName : enclosingSimpleNames()) {
+ builder.append(enclosingSimpleName).append('.');
+ }
+ fullyQualifiedName = builder.append(simpleName()).toString();
+ }
+ return fullyQualifiedName;
+ }
+
+ /**
+ * Equivalent to {@link #classFileName(char) classFileName('$')}
+ */
+ public String classFileName() {
+ return classFileName('$');
+ }
+
+ /**
+ * Returns the class name (excluding package).
+ *
+ * <p>The returned value includes the names of its enclosing classes (if any) but not the package
+ * name. e.g. {@code fromClass(Map.Entry.class).classFileName('_')} will return {@code Map_Entry}.
+ */
+ public String classFileName(char separator) {
+ StringBuilder builder = new StringBuilder();
+ for (String enclosingSimpleName : enclosingSimpleNames) {
+ builder.append(enclosingSimpleName).append(separator);
+ }
+ return builder.append(simpleName()).toString();
+ }
+
+ public ClassName topLevelClassName() {
+ Iterator<String> enclosingIterator = enclosingSimpleNames().iterator();
+ return enclosingIterator.hasNext()
+ ? new ClassName(packageName(), ImmutableList.<String>of(),
+ enclosingIterator.next())
+ : this;
+ }
+
+ public ClassName nestedClassNamed(String memberClassName) {
+ checkNotNull(memberClassName);
+ checkArgument(SourceVersion.isIdentifier(memberClassName));
+ return new ClassName(packageName(),
+ new ImmutableList.Builder<String>()
+ .addAll(enclosingSimpleNames())
+ .add(simpleName())
+ .build(),
+ memberClassName);
+ }
+
+ public ClassName peerNamed(String peerClassName) {
+ checkNotNull(peerClassName);
+ checkArgument(SourceVersion.isIdentifier(peerClassName));
+ return new ClassName(packageName(), enclosingSimpleNames(), peerClassName);
+ }
+
+ /**
+ * Returns a parameterized type name with this as its raw type if {@code parameters} is not empty.
+ * If {@code parameters} is empty, returns this object.
+ */
+ public TypeName withTypeParameters(List<? extends TypeName> parameters) {
+ return parameters.isEmpty() ? this : ParameterizedTypeName.create(this, parameters);
+ }
+
+ private static final ImmutableSet<NestingKind> ACCEPTABLE_NESTING_KINDS =
+ Sets.immutableEnumSet(TOP_LEVEL, MEMBER);
+
+ public static ClassName fromTypeElement(TypeElement element) {
+ checkNotNull(element);
+ checkArgument(ACCEPTABLE_NESTING_KINDS.contains(element.getNestingKind()));
+ String simpleName = element.getSimpleName().toString();
+ List<String> enclosingNames = new ArrayList<String>();
+ Element current = element.getEnclosingElement();
+ while (current.getKind().isClass() || current.getKind().isInterface()) {
+ checkArgument(ACCEPTABLE_NESTING_KINDS.contains(element.getNestingKind()));
+ enclosingNames.add(current.getSimpleName().toString());
+ current = current.getEnclosingElement();
+ }
+ PackageElement packageElement = getPackage(current);
+ Collections.reverse(enclosingNames);
+ return new ClassName(packageElement.getQualifiedName().toString(),
+ ImmutableList.copyOf(enclosingNames), simpleName);
+ }
+
+ public static ClassName fromClass(Class<?> clazz) {
+ checkNotNull(clazz);
+ List<String> enclosingNames = new ArrayList<String>();
+ Class<?> current = clazz.getEnclosingClass();
+ while (current != null) {
+ enclosingNames.add(current.getSimpleName());
+ current = current.getEnclosingClass();
+ }
+ Collections.reverse(enclosingNames);
+ return create(clazz.getPackage().getName(), enclosingNames, clazz.getSimpleName());
+ }
+
+ private static PackageElement getPackage(Element type) {
+ while (type.getKind() != ElementKind.PACKAGE) {
+ type = type.getEnclosingElement();
+ }
+ return (PackageElement) type;
+ }
+
+ /**
+ * Returns a new {@link ClassName} instance for the given fully-qualified class name string. This
+ * method assumes that the input is ASCII and follows typical Java style (lower-case package
+ * names, upper-camel-case class names) and may produce incorrect results or throw
+ * {@link IllegalArgumentException} otherwise. For that reason, {@link #fromClass(Class)} and
+ * {@link #fromClass(Class)} should be preferred as they can correctly create {@link ClassName}
+ * instances without such restrictions.
+ */
+ public static ClassName bestGuessFromString(String classNameString) {
+ checkNotNull(classNameString);
+ List<String> parts = Splitter.on('.').splitToList(classNameString);
+ int firstClassPartIndex = -1;
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts.get(i);
+ checkArgument(SourceVersion.isIdentifier(part));
+ char firstChar = part.charAt(0);
+ if (Ascii.isLowerCase(firstChar)) {
+ // looks like a package part
+ if (firstClassPartIndex >= 0) {
+ throw new IllegalArgumentException("couldn't make a guess for " + classNameString);
+ }
+ } else if (Ascii.isUpperCase(firstChar)) {
+ // looks like a class part
+ if (firstClassPartIndex < 0) {
+ firstClassPartIndex = i;
+ }
+ } else {
+ throw new IllegalArgumentException("couldn't make a guess for " + classNameString);
+ }
+ }
+ int lastIndex = parts.size() - 1;
+ return new ClassName(
+ Joiner.on('.').join(parts.subList(0, firstClassPartIndex)),
+ firstClassPartIndex == lastIndex
+ ? ImmutableList.<String>of()
+ : ImmutableList.copyOf(parts.subList(firstClassPartIndex, lastIndex)),
+ parts.get(lastIndex));
+ }
+
+ public static ClassName create(
+ String packageName, List<String> enclosingSimpleNames, String simpleName) {
+ return new ClassName(packageName, ImmutableList.copyOf(enclosingSimpleNames),
+ simpleName);
+ }
+
+ public static ClassName create(String packageName, String simpleName) {
+ return new ClassName(packageName, ImmutableList.<String>of(), simpleName);
+ }
+
+ @Override
+ public String toString() {
+ return canonicalName();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(context.sourceReferenceForClassName(this));
+ return appendable;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof ClassName) {
+ ClassName that = (ClassName) obj;
+ return this.packageName.equals(that.packageName)
+ && this.enclosingSimpleNames.equals(that.enclosingSimpleNames)
+ && this.simpleName.equals(that.simpleName);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(packageName, enclosingSimpleNames, simpleName);
+ }
+
+ @Override
+ public int compareTo(ClassName o) {
+ return canonicalName().compareTo(o.canonicalName());
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of(this);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java
new file mode 100644
index 0000000..edaba3a
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ClassWriter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkState;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public final class ClassWriter extends TypeWriter {
+ private Optional<TypeName> superclass;
+ private final List<ConstructorWriter> constructorWriters;
+ private final List<TypeVariableName> typeParameters;
+
+ ClassWriter(ClassName className) {
+ super(className);
+ this.superclass = Optional.absent();
+ this.constructorWriters = Lists.newArrayList();
+ this.typeParameters = Lists.newArrayList();
+ }
+
+ public void setSuperclass(TypeName typeReference) {
+ checkState(!superclass.isPresent());
+ superclass = Optional.of(typeReference);
+ }
+
+ /**
+ * If {@code supertype} is a class, makes this class extend it; if it is an interface, makes this
+ * class implement it.
+ */
+ public void setSupertype(TypeElement supertype) {
+ switch (supertype.getKind()) {
+ case CLASS:
+ setSuperclass(ClassName.fromTypeElement(supertype));
+ break;
+ case INTERFACE:
+ addImplementedType(supertype);
+ break;
+ default:
+ throw new IllegalArgumentException(supertype + " must be a class or interface");
+ }
+ }
+
+ public ConstructorWriter addConstructor() {
+ ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
+ constructorWriters.add(constructorWriter);
+ return constructorWriter;
+ }
+
+ public void addTypeParameter(TypeVariableName typeVariableName) {
+ this.typeParameters.add(typeVariableName);
+ }
+
+ public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) {
+ Iterables.addAll(typeParameters, typeVariableNames);
+ }
+
+ public List<TypeVariableName> typeParameters() {
+ return ImmutableList.copyOf(typeParameters);
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("class ").append(name.simpleName());
+ Writables.join(", ", typeParameters, "<", ">", appendable, context);
+ if (superclass.isPresent()) {
+ appendable.append(" extends ");
+ superclass.get().write(appendable, context);
+ }
+ Writables.join(", ", implementedTypes, " implements ", "", appendable, context);
+ appendable.append(" {");
+ if (!fieldWriters.isEmpty()) {
+ appendable.append('\n');
+ }
+ for (VariableWriter fieldWriter : fieldWriters.values()) {
+ fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
+ }
+ for (ConstructorWriter constructorWriter : constructorWriters) {
+ appendable.append('\n');
+ if (!isDefaultConstructor(constructorWriter)) {
+ constructorWriter.write(new IndentingAppendable(appendable), context);
+ }
+ }
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ private static final Set<Modifier> VISIBILIY_MODIFIERS =
+ Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
+
+ private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
+ return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
+ .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
+ && constructorWriter.body().isEmpty();
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(fieldWriters.values())
+ .append(constructorWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(superclass.asSet())
+ .append(annotations)
+ .append(typeParameters)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java
new file mode 100644
index 0000000..387c1dd
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ConstructorWriter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public final class ConstructorWriter extends Modifiable implements Writable, HasClassReferences {
+ private final String name;
+ private final Map<String, VariableWriter> parameterWriters;
+ private final BlockWriter blockWriter;
+
+ ConstructorWriter(String name) {
+ this.name = name;
+ this.parameterWriters = Maps.newLinkedHashMap();
+ this.blockWriter = new BlockWriter();
+ }
+
+ public VariableWriter addParameter(Class<?> type, String name) {
+ return addParameter(ClassName.fromClass(type), name);
+ }
+
+ public VariableWriter addParameter(TypeElement type, String name) {
+ return addParameter(ClassName.fromTypeElement(type), name);
+ }
+
+ public VariableWriter addParameter(TypeWriter type, String name) {
+ return addParameter(type.name, name);
+ }
+
+ public VariableWriter addParameter(TypeName type, String name) {
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ public Map<String, TypeName> parameters() {
+ ImmutableMap.Builder<String, TypeName> params = ImmutableMap.builder();
+ for (Map.Entry<String, VariableWriter> entry : parameterWriters.entrySet()) {
+ params.put(entry.getKey(), entry.getValue().type());
+ }
+ return params.build();
+ }
+
+ public BlockWriter body() {
+ return blockWriter;
+ }
+
+ private VariableWriter addParameter(ClassName type, String name) {
+ checkArgument(!parameterWriters.containsKey(name));
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(parameterWriters.values())
+ .append(annotations)
+ .append(blockWriter)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append(name).append('(');
+ Writables.join(", ", parameterWriters.values(), appendable, context);
+ appendable.append(") {");
+ blockWriter.write(new IndentingAppendable(appendable), context);
+ return appendable.append("}\n");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java
new file mode 100644
index 0000000..4ab017d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/EnumWriter.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+import static com.google.common.base.Preconditions.checkState;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public final class EnumWriter extends TypeWriter {
+ private final Map<String, ConstantWriter> constantWriters = Maps.newLinkedHashMap();
+ private final List<ConstructorWriter> constructorWriters = Lists.newArrayList();
+
+ EnumWriter(ClassName name) {
+ super(name);
+ }
+
+ public ConstantWriter addConstant(String name) {
+ ConstantWriter constantWriter = new ConstantWriter(name);
+ constantWriters.put(name, constantWriter);
+ return constantWriter;
+ }
+
+ public ConstructorWriter addConstructor() {
+ ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
+ constructorWriters.add(constructorWriter);
+ return constructorWriter;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("enum ").append(name.simpleName());
+ Iterator<TypeName> implementedTypesIterator = implementedTypes.iterator();
+ if (implementedTypesIterator.hasNext()) {
+ appendable.append(" implements ");
+ implementedTypesIterator.next().write(appendable, context);
+ while (implementedTypesIterator.hasNext()) {
+ appendable.append(", ");
+ implementedTypesIterator.next().write(appendable, context);
+ }
+ }
+ appendable.append(" {");
+
+ checkState(!constantWriters.isEmpty(), "Cannot write an enum with no constants.");
+ appendable.append('\n');
+ ImmutableList<ConstantWriter> constantWriterList =
+ ImmutableList.copyOf(constantWriters.values());
+ for (ConstantWriter constantWriter
+ : constantWriterList.subList(0, constantWriterList.size() - 1)) {
+ constantWriter.write(appendable, context);
+ appendable.append(",\n");
+ }
+ constantWriterList.get(constantWriterList.size() - 1).write(appendable, context);
+ appendable.append(";\n");
+
+ if (!fieldWriters.isEmpty()) {
+ appendable.append('\n');
+ }
+ for (VariableWriter fieldWriter : fieldWriters.values()) {
+ fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
+ }
+ for (ConstructorWriter constructorWriter : constructorWriters) {
+ appendable.append('\n');
+ if (!isDefaultConstructor(constructorWriter)) {
+ constructorWriter.write(new IndentingAppendable(appendable), context);
+ }
+ }
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ private static final Set<Modifier> VISIBILIY_MODIFIERS =
+ Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
+
+ private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
+ return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
+ .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
+ && constructorWriter.body().isEmpty();
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(constantWriters.values())
+ .append(fieldWriters.values())
+ .append(constructorWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+
+ public static final class ConstantWriter implements Writable, HasClassReferences {
+ private final String name;
+ private final List<Snippet> constructorSnippets;
+
+ private ConstantWriter(String name) {
+ this.name = name;
+ this.constructorSnippets = Lists.newArrayList();
+ }
+
+ ConstantWriter addArgument(Snippet snippet) {
+ constructorSnippets.add(snippet);
+ return this;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(name);
+ Iterator<Snippet> snippetIterator = constructorSnippets.iterator();
+ if (snippetIterator.hasNext()) {
+ appendable.append('(');
+ snippetIterator.next().write(appendable, context);
+ while (snippetIterator.hasNext()) {
+ appendable.append(", ");
+ snippetIterator.next().write(appendable, context);
+ }
+ appendable.append(')');
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(constructorSnippets)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java
new file mode 100644
index 0000000..b45e5d9
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/FieldWriter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Set;
+
+public final class FieldWriter extends VariableWriter {
+ private Optional<Snippet> initializer;
+
+ FieldWriter(TypeName type, String name) {
+ super(type, name);
+ this.initializer = Optional.absent();
+ }
+
+ public void setInitializer(Snippet initializer) {
+ this.initializer = Optional.of(initializer);
+ }
+
+ public void setInitializer(String initializer, Object... args) {
+ this.initializer = Optional.of(Snippet.format(initializer, args));
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ super.write(appendable, context);
+ if (initializer.isPresent()) {
+ appendable.append(" = ");
+ initializer.get().write(appendable, context);
+ }
+ appendable.append(';');
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ Iterable<? extends HasClassReferences> concat =
+ Iterables.concat(ImmutableList.of(type()), initializer.asSet(), annotations);
+ return FluentIterable.from(concat)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java b/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java
new file mode 100644
index 0000000..e463ea2
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/HasClassReferences.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import java.util.Set;
+
+public interface HasClassReferences {
+ Set<ClassName> referencedClasses();
+
+ static final Function<HasClassReferences, Set<ClassName>> COMBINER =
+ new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ };
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java
new file mode 100644
index 0000000..a6909ed
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/HasTypeName.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+interface HasTypeName {
+ TypeName name();
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java b/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java
new file mode 100644
index 0000000..d96f8a3
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/IndentingAppendable.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.AbstractIterator;
+import java.io.IOException;
+import java.util.Iterator;
+
+final class IndentingAppendable implements Appendable {
+ private final String indentation;
+ private final Appendable delegate;
+ private boolean requiresIndent = true;
+
+ IndentingAppendable(Appendable delegate) {
+ this(" ", delegate);
+ }
+
+ IndentingAppendable(String indentation, Appendable delegate) {
+ this.indentation = indentation;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Appendable append(CharSequence csq) throws IOException {
+ return append(csq, 0, csq.length());
+ }
+
+ @Override
+ public Appendable append(CharSequence csq, int start, int end) throws IOException {
+ Iterator<CharSequence> lines = lines(csq, start, end);
+ while (lines.hasNext()) {
+ CharSequence line = lines.next();
+ maybeIndent();
+ delegate.append(line);
+ if (line.charAt(line.length() - 1) == '\n') {
+ requiresIndent = true;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public Appendable append(char c) throws IOException {
+ maybeIndent();
+ delegate.append(c);
+ if (c == '\n') {
+ requiresIndent = true;
+ }
+ return this;
+ }
+
+ void maybeIndent() throws IOException {
+ if (requiresIndent) {
+ delegate.append(indentation);
+ }
+ requiresIndent = false;
+ }
+
+ private static Iterator<CharSequence> lines(
+ final CharSequence csq, final int start, final int end) {
+ return new AbstractIterator<CharSequence>() {
+ int index = start;
+
+ @Override protected CharSequence computeNext() {
+ int nextStart = index;
+ while (index < end && csq.charAt(index) != '\n') {
+ index++;
+ }
+ if (index < end && csq.charAt(index) == '\n') {
+ index++;
+ }
+ int nextEnd = index;
+ return nextStart >= end
+ ? endOfData()
+ : csq.subSequence(nextStart, nextEnd);
+ }
+ };
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java
new file mode 100644
index 0000000..ffcfc75
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/InterfaceWriter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public final class InterfaceWriter extends TypeWriter {
+ private final List<TypeVariableName> typeVariables;
+ InterfaceWriter(ClassName name) {
+ super(name);
+ this.typeVariables = Lists.newArrayList();
+ }
+
+ public void addTypeVariable(TypeVariableName typeVariable) {
+ this.typeVariables.add(typeVariable);
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet());
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable).append("interface ").append(name.simpleName());
+ if (!typeVariables.isEmpty()) {
+ appendable.append('<');
+ Joiner.on(", ").appendTo(appendable, typeVariables);
+ appendable.append('>');
+ }
+ Iterator<TypeName> implementedTypesIterator = implementedTypes.iterator();
+ if (implementedTypesIterator.hasNext()) {
+ appendable.append(" extends ");
+ implementedTypesIterator.next().write(appendable, context);
+ while (implementedTypesIterator.hasNext()) {
+ appendable.append(", ");
+ implementedTypesIterator.next().write(appendable, context);
+ }
+ }
+ appendable.append(" {");
+ for (MethodWriter methodWriter : methodWriters) {
+ appendable.append('\n');
+ methodWriter.write(new IndentingAppendable(appendable), context);
+ }
+ for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
+ appendable.append('\n');
+ nestedTypeWriter.write(new IndentingAppendable(appendable), context);
+ }
+ appendable.append("}\n");
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(nestedTypeWriters)
+ .append(methodWriters)
+ .append(implementedTypes)
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java
new file mode 100644
index 0000000..5977371
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/JavaWriter.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import com.google.common.io.CharSink;
+import com.google.common.io.CharSource;
+import com.google.googlejavaformat.java.Formatter;
+import com.google.googlejavaformat.java.FormatterException;
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.PackageElement;
+import javax.tools.JavaFileObject;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Writes a single compilation unit.
+ */
+public final class JavaWriter {
+ public static JavaWriter inPackage(String packageName) {
+ return new JavaWriter(packageName);
+ }
+
+ public static JavaWriter inPackage(Package enclosingPackage) {
+ return new JavaWriter(enclosingPackage.getName());
+ }
+
+ public static JavaWriter inPackage(PackageElement packageElement) {
+ return new JavaWriter(packageElement.getQualifiedName().toString());
+ }
+
+ private final String packageName;
+ // TODO(gak): disallow multiple types in a file?
+ private final List<TypeWriter> typeWriters;
+ private final List<ClassName> explicitImports;
+
+ private JavaWriter(String packageName) {
+ this.packageName = packageName;
+ this.typeWriters = Lists.newArrayList();
+ this.explicitImports = Lists.newArrayList();
+ }
+
+ public List<TypeWriter> getTypeWriters() {
+ return unmodifiableList(typeWriters);
+ }
+
+ public JavaWriter addImport(Class<?> importedClass) {
+ explicitImports.add(ClassName.fromClass(importedClass));
+ return this;
+ }
+
+ public ClassWriter addClass(String simpleName) {
+ checkNotNull(simpleName);
+ ClassWriter classWriter = new ClassWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(classWriter);
+ return classWriter;
+ }
+
+ public EnumWriter addEnum(String simpleName) {
+ checkNotNull(simpleName);
+ EnumWriter writer = new EnumWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(writer);
+ return writer;
+ }
+
+ public InterfaceWriter addInterface(String simpleName) {
+ InterfaceWriter writer = new InterfaceWriter(ClassName.create(packageName, simpleName));
+ typeWriters.add(writer);
+ return writer;
+ }
+
+ public <A extends Appendable> A write(A appendable) throws IOException {
+ if (!packageName.isEmpty()) {
+ appendable.append("package ").append(packageName).append(";\n\n");
+ }
+
+ // write imports
+ ImmutableSet<ClassName> classNames = FluentIterable.from(typeWriters)
+ .transformAndConcat(new Function<HasClassReferences, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(HasClassReferences input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+
+ ImmutableSortedSet<ClassName> importCandidates = ImmutableSortedSet.<ClassName>naturalOrder()
+ .addAll(explicitImports)
+ .addAll(classNames)
+ .build();
+ ImmutableSet<ClassName> typeNames = FluentIterable.from(typeWriters)
+ .transform(new Function<TypeWriter, ClassName>() {
+ @Override public ClassName apply(TypeWriter input) {
+ return input.name;
+ }
+ })
+ .toSet();
+
+ ImmutableSet.Builder<String> declaredSimpleNamesBuilder = ImmutableSet.builder();
+ Deque<TypeWriter> declaredTypes = new ArrayDeque<>(typeWriters);
+ while (!declaredTypes.isEmpty()) {
+ TypeWriter currentType = declaredTypes.pop();
+ declaredSimpleNamesBuilder.add(currentType.name().simpleName());
+ declaredTypes.addAll(currentType.nestedTypeWriters);
+ }
+
+ ImmutableSet<String> declaredSimpleNames = declaredSimpleNamesBuilder.build();
+
+ BiMap<String, ClassName> importedClassIndex = HashBiMap.create();
+ for (ClassName className : importCandidates) {
+ if (!(className.packageName().equals(packageName)
+ && !className.enclosingClassName().isPresent())
+ && !(className.packageName().equals("java.lang")
+ && className.enclosingSimpleNames().isEmpty())
+ && !typeNames.contains(className.topLevelClassName())) {
+ Optional<ClassName> importCandidate = Optional.of(className);
+ while (importCandidate.isPresent()
+ && (importedClassIndex.containsKey(importCandidate.get().simpleName())
+ || declaredSimpleNames.contains(importCandidate.get().simpleName()))) {
+ importCandidate = importCandidate.get().enclosingClassName();
+ }
+ if (importCandidate.isPresent()) {
+ appendable.append("import ").append(importCandidate.get().canonicalName()).append(";\n");
+ importedClassIndex.put(importCandidate.get().simpleName(), importCandidate.get());
+ }
+ }
+ }
+
+ appendable.append('\n');
+
+ CompilationUnitContext context =
+ new CompilationUnitContext(packageName, ImmutableSet.copyOf(importedClassIndex.values()));
+
+ // write types
+ for (TypeWriter typeWriter : typeWriters) {
+ typeWriter.write(appendable, context.createSubcontext(typeNames)).append('\n');
+ }
+ return appendable;
+ }
+
+ public void file(Filer filer, Iterable<? extends Element> originatingElements)
+ throws IOException {
+ file(filer, Iterables.getOnlyElement(typeWriters).name.canonicalName(), originatingElements);
+ }
+
+ public void file(Filer filer, CharSequence name, Iterable<? extends Element> originatingElements)
+ throws IOException {
+ final JavaFileObject sourceFile = filer.createSourceFile(name,
+ Iterables.toArray(originatingElements, Element.class));
+ try {
+ new Formatter().formatSource(
+ CharSource.wrap(write(new StringBuilder())),
+ new CharSink() {
+ @Override public Writer openStream() throws IOException {
+ return sourceFile.openWriter();
+ }
+ });
+ } catch (FormatterException e) {
+ throw new IllegalStateException(
+ "The writer produced code that could not be parsed by the formatter", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return write(new StringBuilder()).toString();
+ } catch (IOException e) {
+ throw new AssertionError();
+ }
+ }
+
+ static final class CompilationUnitContext implements Context {
+ private final String packageName;
+ private final ImmutableSortedSet<ClassName> visibleClasses;
+
+ CompilationUnitContext(String packageName, Set<ClassName> visibleClasses) {
+ this.packageName = packageName;
+ this.visibleClasses =
+ ImmutableSortedSet.copyOf(Ordering.natural().reverse(), visibleClasses);
+ }
+
+ @Override
+ public Context createSubcontext(Set<ClassName> newTypes) {
+ return new CompilationUnitContext(packageName, Sets.union(visibleClasses, newTypes));
+ }
+
+ @Override
+ public String sourceReferenceForClassName(ClassName className) {
+ if (isImported(className)) {
+ return className.simpleName();
+ }
+ Optional<ClassName> enclosingClassName = className.enclosingClassName();
+ while (enclosingClassName.isPresent()) {
+ if (isImported(enclosingClassName.get())) {
+ return enclosingClassName.get().simpleName()
+ + className.canonicalName()
+ .substring(enclosingClassName.get().canonicalName().length());
+ }
+ enclosingClassName = enclosingClassName.get().enclosingClassName();
+ }
+ return className.canonicalName();
+ }
+
+ private boolean collidesWithVisibleClass(ClassName className) {
+ return collidesWithVisibleClass(className.simpleName());
+ }
+
+ private boolean collidesWithVisibleClass(String simpleName) {
+ return FluentIterable.from(visibleClasses)
+ .transform(new Function<ClassName, String>() {
+ @Override public String apply(ClassName input) {
+ return input.simpleName();
+ }
+ })
+ .contains(simpleName);
+ }
+
+ private boolean isImported(ClassName className) {
+ return (packageName.equals(className.packageName())
+ && !className.enclosingClassName().isPresent()
+ && !collidesWithVisibleClass(className)) // need to account for scope & hiding
+ || visibleClasses.contains(className)
+ || (className.packageName().equals("java.lang")
+ && className.enclosingSimpleNames().isEmpty());
+ }
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java
new file mode 100644
index 0000000..eb4ff8d
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/MethodWriter.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.element.TypeElement;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public final class MethodWriter extends Modifiable implements HasClassReferences, Writable {
+ private final TypeName returnType;
+ private final String name;
+ private final Map<String, VariableWriter> parameterWriters;
+ private final List<TypeVariableName> typeParameters;
+ private Optional<BlockWriter> body;
+
+ MethodWriter(TypeName returnType, String name) {
+ this.returnType = returnType;
+ this.name = name;
+ this.parameterWriters = Maps.newLinkedHashMap();
+ this.typeParameters = Lists.newArrayList();
+ this.body = Optional.absent();
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public TypeName returnType() {
+ return returnType;
+ }
+
+ public void addTypeParameter(TypeVariableName typeVariableName) {
+ this.typeParameters.add(typeVariableName);
+ }
+
+ public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) {
+ Iterables.addAll(typeParameters, typeVariableNames);
+ }
+
+ public VariableWriter addParameter(Class<?> type, String name) {
+ return addParameter(ClassName.fromClass(type), name);
+ }
+
+ public VariableWriter addParameter(TypeElement type, String name) {
+ return addParameter(ClassName.fromTypeElement(type), name);
+ }
+
+ public VariableWriter addParameter(TypeWriter type, String name) {
+ return addParameter(type.name, name);
+ }
+
+ public VariableWriter addParameter(TypeName type, String name) {
+ checkArgument(!parameterWriters.containsKey(name));
+ VariableWriter parameterWriter = new VariableWriter(type, name);
+ parameterWriters.put(name, parameterWriter);
+ return parameterWriter;
+ }
+
+ public BlockWriter body() {
+ if (body.isPresent()) {
+ return body.get();
+ } else {
+ BlockWriter blockWriter = new BlockWriter();
+ body = Optional.of(blockWriter);
+ return blockWriter;
+ }
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable);
+ Writables.join(", ", typeParameters, "<", "> ", appendable, context);
+ returnType.write(appendable, context);
+ appendable.append(' ').append(name).append('(');
+ Writables.join(", ", parameterWriters.values(), appendable, context);
+ appendable.append(")");
+ if (body.isPresent()) {
+ appendable.append(" {");
+ body.get().write(new IndentingAppendable(appendable), context);
+ appendable.append("}\n");
+ } else {
+ appendable.append(";\n");
+ }
+ return appendable;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(parameterWriters.values())
+ .append(returnType)
+ .append(body.asSet())
+ .append(annotations)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java b/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java
new file mode 100644
index 0000000..bb4c6ff
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Modifiable.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+public abstract class Modifiable {
+ final Set<Modifier> modifiers;
+ final List<AnnotationWriter> annotations;
+
+ Modifiable() {
+ this.modifiers = EnumSet.noneOf(Modifier.class);
+ this.annotations = Lists.newArrayList();
+ }
+
+ public void addModifiers(Modifier first, Modifier... rest) {
+ addModifiers(Lists.asList(first, rest));
+ }
+
+ public void addModifiers(Iterable<Modifier> modifiers) {
+ Iterables.addAll(this.modifiers, modifiers);
+ }
+
+ public AnnotationWriter annotate(ClassName annotation) {
+ AnnotationWriter annotationWriter = new AnnotationWriter(annotation);
+ this.annotations.add(annotationWriter);
+ return annotationWriter;
+ }
+
+ public AnnotationWriter annotate(Class<? extends Annotation> annotation) {
+ return annotate(ClassName.fromClass(annotation));
+ }
+
+ Appendable writeModifiers(Appendable appendable) throws IOException {
+ for (Modifier modifier : modifiers) {
+ appendable.append(modifier.toString()).append(' ');
+ }
+ return appendable;
+ }
+
+ Appendable writeAnnotations(Appendable appendable, Context context) throws IOException {
+ for (AnnotationWriter annotationWriter : annotations) {
+ annotationWriter.write(appendable, context).append('\n');
+ }
+ return appendable;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java b/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java
new file mode 100644
index 0000000..0d3588b
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/NullName.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+
+enum NullName implements TypeName {
+ NULL;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append("null");
+ }
+
+ @Override
+ public String toString() {
+ return "null";
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java
new file mode 100644
index 0000000..e46a961
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/ParameterizedTypeName.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+
+public final class ParameterizedTypeName implements TypeName {
+ private final ClassName type;
+ private final ImmutableList<TypeName> parameters;
+
+ ParameterizedTypeName(ClassName type, Iterable<? extends TypeName> parameters) {
+ this.type = type;
+ this.parameters = ImmutableList.<TypeName>copyOf(parameters);
+ }
+
+ public ClassName type() {
+ return type;
+ }
+
+ public ImmutableList<TypeName> parameters() {
+ return parameters;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>()
+ .add(type);
+ for (TypeName parameter : parameters) {
+ builder.addAll(parameter.referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(context.sourceReferenceForClassName(type));
+ Iterator<? extends TypeName> parameterIterator = parameters.iterator();
+ verify(parameterIterator.hasNext(), type.toString());
+ appendable.append('<');
+ parameterIterator.next().write(appendable, context);
+ while (parameterIterator.hasNext()) {
+ appendable.append(", ");
+ parameterIterator.next().write(appendable, context);
+ }
+ appendable.append('>');
+ return appendable;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ParameterizedTypeName) {
+ ParameterizedTypeName that = (ParameterizedTypeName) obj;
+ return this.type.equals(that.type)
+ && this.parameters.equals(that.parameters);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(type, parameters);
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ public static ParameterizedTypeName create(ClassName className,
+ TypeName... parameters) {
+ return new ParameterizedTypeName(className, ImmutableList.copyOf(parameters));
+ }
+
+ public static ParameterizedTypeName create(ClassName className,
+ Iterable<? extends TypeName> parameters) {
+ return new ParameterizedTypeName(className, ImmutableList.copyOf(parameters));
+ }
+
+ public static ParameterizedTypeName create(Class<?> parameterizedClass,
+ TypeName... parameters) {
+ checkArgument(parameterizedClass.getTypeParameters().length == parameters.length);
+ return new ParameterizedTypeName(ClassName.fromClass(parameterizedClass),
+ ImmutableList.copyOf(parameters));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java b/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java
new file mode 100644
index 0000000..94961dd
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/PrimitiveName.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+import javax.lang.model.type.PrimitiveType;
+
+public enum PrimitiveName implements TypeName {
+ BOOLEAN, BYTE, SHORT, INT, LONG, CHAR, FLOAT, DOUBLE;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public String toString() {
+ return Ascii.toLowerCase(name());
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append(toString());
+ }
+
+ static PrimitiveName forTypeMirror(PrimitiveType mirror) {
+ switch (mirror.getKind()) {
+ case BOOLEAN:
+ return BOOLEAN;
+ case BYTE:
+ return BYTE;
+ case SHORT:
+ return SHORT;
+ case INT:
+ return INT;
+ case LONG:
+ return LONG;
+ case CHAR:
+ return CHAR;
+ case FLOAT:
+ return FLOAT;
+ case DOUBLE:
+ return DOUBLE;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ static PrimitiveName forClass(Class<?> primitiveClass) {
+ if (boolean.class.equals(primitiveClass)) {
+ return BOOLEAN;
+ }
+ if (byte.class.equals(primitiveClass)) {
+ return BYTE;
+ }
+ if (short.class.equals(primitiveClass)) {
+ return SHORT;
+ }
+ if (int.class.equals(primitiveClass)) {
+ return INT;
+ }
+ if (long.class.equals(primitiveClass)) {
+ return LONG;
+ }
+ if (char.class.equals(primitiveClass)) {
+ return CHAR;
+ }
+ if (float.class.equals(primitiveClass)) {
+ return FLOAT;
+ }
+ if (double.class.equals(primitiveClass)) {
+ return DOUBLE;
+ }
+ throw new IllegalArgumentException(primitiveClass + " is not a primitive type");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java b/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java
new file mode 100644
index 0000000..80ab944
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Snippet.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.Set;
+
+public abstract class Snippet implements HasClassReferences, Writable {
+
+ abstract ImmutableSet<TypeName> types();
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ @Override
+ public final Set<ClassName> referencedClasses() {
+ return FluentIterable.from(types())
+ .transformAndConcat(
+ new Function<TypeName, Set<ClassName>>() {
+ @Override
+ public Set<ClassName> apply(TypeName input) {
+ return input.referencedClasses();
+ }
+ })
+ .toSet();
+ }
+
+ private static final class BasicSnippet extends Snippet {
+ final String format;
+ final ImmutableSet<TypeName> types;
+ final ImmutableList<Object> args;
+
+ BasicSnippet(String format, ImmutableSet<TypeName> types, ImmutableList<Object> args) {
+ this.format = format;
+ this.types = types;
+ this.args = args;
+ }
+
+ @Override
+ ImmutableSet<TypeName> types() {
+ return types;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ ImmutableList.Builder<Object> formattedArgsBuilder = ImmutableList.builder();
+ for (Object arg : args) {
+ if (arg instanceof Writable) {
+ formattedArgsBuilder.add(((Writable) arg).write(new StringBuilder(), context).toString());
+ } else {
+ formattedArgsBuilder.add(arg);
+ }
+ }
+
+ @SuppressWarnings("resource") // intentionally don't close the formatter
+ Formatter formatter = new Formatter(appendable);
+ formatter.format(format, Iterables.toArray(formattedArgsBuilder.build(), Object.class));
+
+ return appendable;
+ }
+ }
+
+ private static final class CompoundSnippet extends Snippet {
+ final String joinToken;
+ final ImmutableList<Snippet> snippets;
+
+ CompoundSnippet(String joinToken, ImmutableList<Snippet> snippets) {
+ this.joinToken = joinToken;
+ this.snippets = snippets;
+ }
+
+ @Override
+ ImmutableSet<TypeName> types() {
+ return FluentIterable.from(snippets)
+ .transformAndConcat(
+ new Function<Snippet, Iterable<TypeName>>() {
+ @Override
+ public Iterable<TypeName> apply(Snippet input) {
+ return input.types();
+ }
+ })
+ .toSet();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ Iterator<Snippet> snippetIterator = snippets.iterator();
+ if (snippetIterator.hasNext()) {
+ Snippet firstSnippet = snippetIterator.next();
+ firstSnippet.write(appendable, context);
+ while (snippetIterator.hasNext()) {
+ Snippet nextSnippet = snippetIterator.next();
+ appendable.append(joinToken);
+ nextSnippet.write(appendable, context);
+ }
+ }
+ return appendable;
+ }
+ }
+
+ public static Snippet format(String format, Object... args) {
+ ImmutableSet.Builder<TypeName> types = ImmutableSet.builder();
+ for (Object arg : args) {
+ if (arg instanceof Snippet) {
+ types.addAll(((Snippet) arg).types());
+ }
+ if (arg instanceof TypeName) {
+ types.add((TypeName) arg);
+ }
+ if (arg instanceof HasTypeName) {
+ types.add(((HasTypeName) arg).name());
+ }
+ }
+ return new BasicSnippet(format, types.build(), ImmutableList.copyOf(args));
+ }
+
+ public static Snippet format(String format, Iterable<? extends Object> args) {
+ return format(format, Iterables.toArray(args, Object.class));
+ }
+
+ public static Snippet memberSelectSnippet(Iterable<? extends Object> selectors) {
+ return format(Joiner.on('.').join(Collections.nCopies(Iterables.size(selectors), "%s")),
+ selectors);
+ }
+
+ public static Snippet nullCheck(Object thingToCheck) {
+ return format("if (%s == null) { throw new NullPointerException(); } ", thingToCheck);
+ }
+
+ public static Snippet nullCheck(Object thingToCheck, String message) {
+ return format("if (%s == null) { throw new NullPointerException(%s); } ",
+ thingToCheck,
+ StringLiteral.forValue(message));
+ }
+
+ public static Snippet makeParametersSnippet(Iterable<Snippet> parameterSnippets) {
+ return join(", ", parameterSnippets);
+ }
+
+ /**
+ * A snippet that concatenates its arguments with each snippet separated by a new line.
+ */
+ public static Snippet concat(Iterable<Snippet> snippets) {
+ return join("\n", snippets);
+ }
+
+ /**
+ * A snippet that joins its arguments with {@code joiner}.
+ */
+ public static Snippet join(String joinToken, Iterable<Snippet> snippets) {
+ return new CompoundSnippet(joinToken, ImmutableList.copyOf(snippets));
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java b/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java
new file mode 100644
index 0000000..2d059f9
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/StringLiteral.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import java.util.Formatter;
+
+/**
+ * Represents a string literal as found in Java source code.
+ */
+public final class StringLiteral {
+ /** Returns a new {@link StringLiteral} instance for the intended value of the literal. */
+ public static StringLiteral forValue(String value) {
+ return new StringLiteral(value, stringLiteral(value));
+ }
+
+ /** Returns the string literal representing {@code data}, including wrapping quotes. */
+ private static String stringLiteral(String value) {
+ StringBuilder result = new StringBuilder();
+ result.append('"');
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '"':
+ result.append("\\\"");
+ break;
+ case '\\':
+ result.append("\\\\");
+ break;
+ case '\b':
+ result.append("\\b");
+ break;
+ case '\t':
+ result.append("\\t");
+ break;
+ case '\n':
+ result.append("\\n");
+ break;
+ case '\f':
+ result.append("\\f");
+ break;
+ case '\r':
+ result.append("\\r");
+ break;
+ default:
+ if (Character.isISOControl(c)) {
+ new Formatter(result).format("\\u%04x", (int) c);
+ } else {
+ result.append(c);
+ }
+ }
+ }
+ result.append('"');
+ return result.toString();
+ }
+
+ private final String value;
+ private final String literal;
+
+ private StringLiteral(String value, String literal) {
+ this.value = value;
+ this.literal = literal;
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public String literal() {
+ return literal;
+ }
+
+ @Override
+ public String toString() {
+ return literal;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof StringLiteral) {
+ return this.value.equals(((StringLiteral) obj).value);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java
new file mode 100644
index 0000000..e0daf53
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeName.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+public interface TypeName extends HasClassReferences, Writable {
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java
new file mode 100644
index 0000000..4bc2347
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeNames.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+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.WildcardType;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+public final class TypeNames {
+ static final Function<TypeMirror, TypeName> FOR_TYPE_MIRROR =
+ new Function<TypeMirror, TypeName>() {
+ @Override public TypeName apply(TypeMirror input) {
+ return forTypeMirror(input);
+ }
+ };
+
+ public static TypeName forClass(Class<?> clazz) {
+ if (clazz.isPrimitive()) {
+ return PrimitiveName.forClass(clazz);
+ } else if (void.class.equals(clazz)) {
+ return VoidName.VOID;
+ } else if (clazz.isArray()) {
+ return new ArrayTypeName(forClass(clazz.getComponentType()));
+ } else {
+ return ClassName.fromClass(clazz);
+ }
+ }
+
+ public static TypeName forTypeMirror(TypeMirror mirror) {
+ return mirror.accept(new SimpleTypeVisitor6<TypeName, Void>() {
+ @Override
+ protected TypeName defaultAction(TypeMirror e, Void p) {
+ throw new IllegalArgumentException(e.toString());
+ }
+
+ @Override
+ public TypeName visitTypeVariable(TypeVariable t, Void p) {
+ return TypeVariableName.fromTypeVariable(t);
+ }
+
+ @Override
+ public ArrayTypeName visitArray(ArrayType t, Void p) {
+ return new ArrayTypeName(t.getComponentType().accept(this, null));
+ }
+
+ @Override
+ public TypeName visitDeclared(DeclaredType t, Void p) {
+ return t.getTypeArguments().isEmpty()
+ ? ClassName.fromTypeElement((TypeElement) t.asElement())
+ : new ParameterizedTypeName(
+ ClassName.fromTypeElement((TypeElement) t.asElement()),
+ FluentIterable.from(t.getTypeArguments()).transform(FOR_TYPE_MIRROR));
+ }
+
+ @Override
+ public PrimitiveName visitPrimitive(PrimitiveType t, Void p) {
+ return PrimitiveName.forTypeMirror(t);
+ }
+
+ @Override
+ public WildcardName visitWildcard(WildcardType t, Void p) {
+ return WildcardName.forTypeMirror(t);
+ }
+
+ @Override
+ public NullName visitNull(NullType t, Void p) {
+ return NullName.NULL;
+ }
+
+ @Override
+ public TypeName visitNoType(NoType t, Void p) {
+ switch (t.getKind()) {
+ case VOID:
+ return VoidName.VOID;
+ case PACKAGE:
+ throw new IllegalArgumentException();
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }, null);
+ }
+
+ private TypeNames() {
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java
new file mode 100644
index 0000000..c6ee533
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeVariableName.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+
+public final class TypeVariableName implements TypeName {
+ private final CharSequence name;
+ private final Iterable<? extends TypeName> extendsBounds;
+
+ TypeVariableName(CharSequence name, Iterable<? extends TypeName> extendsBounds) {
+ this.name = name;
+ this.extendsBounds = extendsBounds;
+ }
+
+ public CharSequence name() {
+ return name;
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>();
+ for (TypeName bound : extendsBounds) {
+ builder.addAll(bound.referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append(name);
+ if (!Iterables.isEmpty(extendsBounds)) {
+ appendable.append(" extends ");
+ Iterator<? extends TypeName> iter = extendsBounds.iterator();
+ iter.next().write(appendable, context);
+ while (iter.hasNext()) {
+ appendable.append(" & ");
+ iter.next().write(appendable, context);
+ }
+ }
+ return appendable;
+ }
+
+ @Override
+ public String toString() {
+ return Writables.writeToString(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TypeVariableName) {
+ TypeVariableName that = (TypeVariableName) obj;
+ return this.name.toString().equals(that.name.toString())
+ && this.extendsBounds.equals(that.extendsBounds);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, extendsBounds);
+ }
+
+ static TypeVariableName named(CharSequence name) {
+ return new TypeVariableName(name, ImmutableList.<TypeName>of());
+ }
+
+ public static TypeVariableName fromTypeVariable(TypeVariable variable) {
+ // Note: We don't have any use right now for the bounds because these are references
+ // to the type & not the specification of the type itself. We never generate
+ // code with type variables that include upper or lower bounds.
+ return named(variable.asElement().getSimpleName());
+ }
+
+ // TODO(sameb): Consider making this a whole different thing: TypeParameterName since it
+ // has different semantics than a TypeVariable (parameters only have upper bounds).
+ public static TypeVariableName fromTypeParameterElement(TypeParameterElement element) {
+ // We filter out bounds of type Object because those would just clutter the generated code.
+ Iterable<? extends TypeName> bounds =
+ FluentIterable.from(element.getBounds())
+ .filter(new Predicate<TypeMirror>() {
+ @Override public boolean apply(TypeMirror input) {
+ return !MoreTypes.isType(input) || !MoreTypes.isTypeOf(Object.class, input);
+ }
+ })
+ .transform(TypeNames.FOR_TYPE_MIRROR);
+ return new TypeVariableName(element.getSimpleName(), bounds);
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java
new file mode 100644
index 0000000..b13d083
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/TypeWriter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Only named types. Doesn't cover anonymous inner classes.
+ */
+public abstract class TypeWriter /* ha ha */ extends Modifiable
+ implements Writable, HasTypeName, HasClassReferences {
+ final ClassName name;
+ final List<TypeName> implementedTypes;
+ final List<MethodWriter> methodWriters;
+ final List<TypeWriter> nestedTypeWriters;
+ final Map<String, FieldWriter> fieldWriters;
+
+ TypeWriter(ClassName name) {
+ this.name = name;
+ this.implementedTypes = Lists.newArrayList();
+ this.methodWriters = Lists.newArrayList();
+ this.nestedTypeWriters = Lists.newArrayList();
+ this.fieldWriters = Maps.newLinkedHashMap();
+ }
+
+ @Override
+ public ClassName name() {
+ return name;
+ }
+
+ public MethodWriter addMethod(TypeWriter returnType, String name) {
+ MethodWriter methodWriter = new MethodWriter(returnType.name, name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(TypeMirror returnType, String name) {
+ MethodWriter methodWriter =
+ new MethodWriter(TypeNames.forTypeMirror(returnType), name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(TypeName returnType, String name) {
+ MethodWriter methodWriter = new MethodWriter(returnType, name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public MethodWriter addMethod(Class<?> returnType, String name) {
+ MethodWriter methodWriter =
+ new MethodWriter(ClassName.fromClass(returnType), name);
+ methodWriters.add(methodWriter);
+ return methodWriter;
+ }
+
+ public ClassWriter addNestedClass(String name) {
+ ClassWriter innerClassWriter = new ClassWriter(this.name.nestedClassNamed(name));
+ nestedTypeWriters.add(innerClassWriter);
+ return innerClassWriter;
+ }
+
+ public void addImplementedType(TypeName typeReference) {
+ implementedTypes.add(typeReference);
+ }
+
+ public void addImplementedType(TypeElement typeElement) {
+ implementedTypes.add(ClassName.fromTypeElement(typeElement));
+ }
+
+ public FieldWriter addField(Class<?> type, String name) {
+ return addField(ClassName.fromClass(type), name);
+ }
+
+ public FieldWriter addField(TypeElement type, String name) {
+ return addField(ClassName.fromTypeElement(type), name);
+ }
+
+ public FieldWriter addField(TypeName type, String name) {
+ String candidateName = name;
+ int differentiator = 1;
+ while (fieldWriters.containsKey(candidateName)) {
+ candidateName = name + differentiator;
+ differentiator++;
+ }
+ FieldWriter fieldWriter = new FieldWriter(type, candidateName);
+ fieldWriters.put(candidateName, fieldWriter);
+ return fieldWriter;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java b/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java
new file mode 100644
index 0000000..58ee1e4
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/VariableWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VariableWriter extends Modifiable implements Writable, HasClassReferences {
+ private final TypeName type;
+ private final String name;
+
+ VariableWriter(TypeName type, String name) {
+ this.type = checkNotNull(type);
+ this.name = checkNotNull(name);
+ }
+
+ public TypeName type() {
+ return type;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ writeAnnotations(appendable, context);
+ writeModifiers(appendable);
+ type.write(appendable, context);
+ return appendable.append(' ').append(name);
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return FluentIterable.from(ImmutableList.<HasClassReferences>of())
+ .append(annotations)
+ .append(type)
+ .transformAndConcat(HasClassReferences.COMBINER)
+ .toSet();
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java b/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java
new file mode 100644
index 0000000..f82a4ca
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/VoidName.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+
+public enum VoidName implements TypeName {
+ VOID;
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public String toString() {
+ return "void";
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append("void");
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java b/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java
new file mode 100644
index 0000000..7756f93
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/WildcardName.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.Set;
+import javax.lang.model.type.WildcardType;
+
+import static dagger.internal.codegen.writer.TypeNames.FOR_TYPE_MIRROR;
+
+public final class WildcardName implements TypeName {
+ private final Optional<TypeName> extendsBound;
+ private final Optional<TypeName> superBound;
+
+ WildcardName(Optional<TypeName> extendsBound,
+ Optional<TypeName> superBound) {
+ this.extendsBound = extendsBound;
+ this.superBound = superBound;
+ }
+
+ static WildcardName forTypeMirror(WildcardType mirror) {
+ return new WildcardName(
+ Optional.fromNullable(mirror.getExtendsBound()).transform(FOR_TYPE_MIRROR),
+ Optional.fromNullable(mirror.getSuperBound()).transform(FOR_TYPE_MIRROR));
+ }
+
+ @Override
+ public Set<ClassName> referencedClasses() {
+ ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>();
+ if (extendsBound.isPresent()) {
+ builder.addAll(extendsBound.get().referencedClasses());
+ }
+ if (superBound.isPresent()) {
+ builder.addAll(superBound.get().referencedClasses());
+ }
+ return builder.build();
+ }
+
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ appendable.append('?');
+ if (extendsBound.isPresent()) {
+ appendable.append(" extends ");
+ extendsBound.get().write(appendable, context);
+ }
+ if (superBound.isPresent()) {
+ appendable.append(" super ");
+ superBound.get().write(appendable, context);
+ }
+ return appendable;
+ }
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java b/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java
new file mode 100644
index 0000000..9a88f43
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Writable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import java.io.IOException;
+import java.util.Set;
+
+interface Writable {
+ interface Context {
+ String sourceReferenceForClassName(ClassName className);
+ Context createSubcontext(Set<ClassName> newTypes);
+ }
+
+ Appendable write(Appendable appendable, Context context) throws IOException;
+}
diff --git a/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java b/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java
new file mode 100644
index 0000000..0186cbf
--- /dev/null
+++ b/compiler/src/main/java/dagger/internal/codegen/writer/Writables.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import dagger.internal.codegen.writer.Writable.Context;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+final class Writables {
+
+ /**
+ * Joins the writables by the given delimiter, writing out the
+ * prefix & suffix if there's at least one element.
+ */
+ static void join(String delimiter, Iterable<? extends Writable> writables,
+ String prefix, String suffix,
+ Appendable appendable, Context context) throws IOException {
+ Iterator<? extends Writable> iter = writables.iterator();
+ if (iter.hasNext()) {
+ appendable.append(prefix);
+ iter.next().write(appendable, context);
+ while (iter.hasNext()) {
+ appendable.append(delimiter);
+ iter.next().write(appendable, context);
+ }
+ appendable.append(suffix);
+ }
+ }
+
+ /** Joins the writables by the given delimiter. */
+ static void join(String delimiter, Iterable<? extends Writable> writables,
+ Appendable appendable, Context context) throws IOException {
+ join(delimiter, writables, "", "", appendable, context);
+ }
+
+ static Writable toStringWritable(final Object object) {
+ return new Writable() {
+ @Override
+ public Appendable write(Appendable appendable, Context context) throws IOException {
+ return appendable.append(object.toString());
+ }
+ };
+ }
+
+ private static final Context DEFAULT_CONTEXT = new Context() {
+ @Override
+ public String sourceReferenceForClassName(ClassName className) {
+ return className.canonicalName();
+ }
+
+ @Override
+ public Context createSubcontext(Set<ClassName> newTypes) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ static String writeToString(Writable writable) {
+ StringBuilder builder = new StringBuilder();
+ try {
+ writable.write(builder, DEFAULT_CONTEXT);
+ } catch (IOException e) {
+ throw new AssertionError("StringBuilder doesn't throw IOException" + e);
+ }
+ return builder.toString();
+ }
+
+ private Writables() {
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java b/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java
new file mode 100644
index 0000000..eaaa595
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/BindingFieldTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.MembersInjector;
+import dagger.internal.codegen.writer.ClassName;
+import dagger.internal.codegen.writer.ParameterizedTypeName;
+import dagger.internal.codegen.writer.TypeName;
+import dagger.internal.codegen.writer.TypeNames;
+import javax.inject.Inject;
+import javax.inject.Provider;
+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.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Test case for {@link FrameworkField}.
+ */
+@RunWith(JUnit4.class)
+public class BindingFieldTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ }
+
+ private ExecutableElement getXConstructor() {
+ TypeElement classElement = elements.getTypeElement(X.class.getCanonicalName());
+ return Iterables.getOnlyElement(
+ ElementFilter.constructorsIn(classElement.getEnclosedElements()));
+ }
+
+ @Test public void frameworkType() {
+ Key key = keyFactory.forInjectConstructorWithResolvedType(
+ getXConstructor().getEnclosingElement().asType());
+ TypeName xClass = TypeNames.forTypeMirror(key.type());
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "test")
+ .frameworkType())
+ .isEqualTo(ParameterizedTypeName.create(
+ ClassName.fromClass(Provider.class), xClass));
+ assertThat(FrameworkField.createWithTypeFromKey(MembersInjector.class,
+ BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key), "test")
+ .frameworkType())
+ .isEqualTo(ParameterizedTypeName.create(
+ ClassName.fromClass(MembersInjector.class), xClass));
+ }
+
+ @Test public void nameSuffix() {
+ Key key = keyFactory.forInjectConstructorWithResolvedType(
+ getXConstructor().getEnclosingElement().asType());
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "foo").name())
+ .isEqualTo("fooProvider");
+ assertThat(FrameworkField.createWithTypeFromKey(Provider.class,
+ BindingKey.create(BindingKey.Kind.CONTRIBUTION, key), "fooProvider").name())
+ .isEqualTo("fooProvider");
+
+ }
+
+ static final class X {
+ @Inject X() {}
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java b/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java
new file mode 100644
index 0000000..cf0e69d
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ComponentBuilderTest.java
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/** Tests for {@link dagger.Component.Builder} */
+@RunWith(JUnit4.class)
+public class ComponentBuilderTest {
+
+ private static final ErrorMessages.ComponentBuilderMessages MSGS =
+ ErrorMessages.ComponentBuilderMessages.INSTANCE;
+
+ @Test
+ public void testEmptyBuilder() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "",
+ " @Component.Builder",
+ " static interface Builder {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import test.SimpleComponent",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static SimpleComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " private static final class Builder implements SimpleComponent.Builder {",
+ " @Override",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testUsesBuildAndSetterNames() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String string() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " String string();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " Builder setTestModule(TestModule testModule);",
+ " TestComponent create();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<String> stringProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static TestComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().create();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.stringProvider = TestModule_StringFactory.create(builder.testModule);",
+ " }",
+ "",
+ " @Override",
+ " public String string() {",
+ " return stringProvider.get();",
+ " }",
+ "",
+ " private static final class Builder implements TestComponent.Builder {",
+ " private TestModule testModule;",
+ "",
+ " @Override",
+ " public TestComponent create() {",
+ " if (testModule == null) {",
+ " this.testModule = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Override",
+ " public Builder setTestModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testIgnoresModulesNotInApi() {
+ JavaFileObject module1 = JavaFileObjects.forSourceLines("test.TestModule1",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule1 {",
+ " @Provides String string() { return null; }",
+ "}");
+ JavaFileObject module2 = JavaFileObjects.forSourceLines("test.TestModule2",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule2 {",
+ " @Provides Integer integer() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = {TestModule1.class, TestModule2.class})",
+ "interface TestComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " Builder testModule1(TestModule1 testModule1);",
+ " TestComponent build();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<String> stringProvider;",
+ " private Provider<Integer> integerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static TestComponent.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.stringProvider = TestModule1_StringFactory.create(builder.testModule1);",
+ " this.integerProvider = TestModule2_IntegerFactory.create(builder.testModule2);",
+ " }",
+ "",
+ " @Override",
+ " public String string() {",
+ " return stringProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Integer integer() {",
+ " return integerProvider.get();",
+ " }",
+ "",
+ " private static final class Builder implements TestComponent.Builder {",
+ " private TestModule1 testModule1;",
+ " private TestModule2 testModule2;",
+ "",
+ " @Override",
+ " public TestComponent build() {",
+ " if (testModule1 == null) {",
+ " this.testModule1 = new TestModule1();",
+ " }",
+ " if (testModule2 == null) {",
+ " this.testModule2 = new TestModule2();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Override",
+ " public Builder testModule1(TestModule1 testModule1) {",
+ " if (testModule1 == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule1 = testModule1;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module1, module2, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void testMoreThanOneBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " static interface Builder {",
+ " SimpleComponent build();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder2 {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOne(),
+ "[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder<T> {",
+ " SimpleComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.generics())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderNotInComponentFails() {
+ JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component.Builder",
+ "interface Builder {}");
+ assertAbout(javaSource()).that(builder)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeInComponent())
+ .in(builder);
+ }
+
+ @Test
+ public void testBuilderMissingBuildMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.missingBuildMethod())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testPrivateBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " private interface Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.isPrivate())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testNonStaticBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " abstract class Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeStatic())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testNonAbstractBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static class Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeAbstract());
+ }
+
+ @Test
+ public void testBuilderOneCxtorWithArgsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static abstract class Builder {",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderMoreThanOneCxtorFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " static abstract class Builder {",
+ " Builder() {}",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderEnumFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " enum Builder {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeClassOrInterface())
+ .in(componentFile);
+ }
+
+ @Test
+ public void testBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " String build();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.buildMustReturnComponentType())
+ .in(componentFile).onLine(11);
+ }
+
+ @Test
+ public void testInheritedBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " String build();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
+ .in(componentFile).onLine(14);
+ }
+
+ @Test
+ public void testTwoBuildMethodsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " SimpleComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testInheritedTwoBuildMethodsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " SimpleComponent create();",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testMoreThanOneArgFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " Builder set(String s, Integer i);",
+ " Builder set(Number n, Double d);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(componentFile).onLine(12)
+ .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(componentFile).onLine(13);
+ }
+
+ @Test
+ public void testInheritedMoreThanOneArgFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " Builder set1(String s, Integer i);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustTakeOneArg(),
+ "set1(java.lang.String,java.lang.Integer)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " String set(Integer i);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testInheritedSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " String set(Integer i);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
+ "set(java.lang.Integer)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testGenericsOnSetterMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
+ .in(componentFile).onLine(12);
+ }
+
+ @Test
+ public void testGenericsOnInheritedSetterMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent {",
+ " SimpleComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
+ .in(componentFile).onLine(15);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " void set1(String s);",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
+ .in(componentFile).onLine(10);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " interface Parent<T> {",
+ " void set1(T t);",
+ " }",
+ "",
+ " @Component.Builder",
+ " interface Builder extends Parent<String> {",
+ " SimpleComponent build();",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(T), set2(java.lang.String)]"))
+ .in(componentFile).onLine(14);
+ }
+
+ @Test
+ public void testExtraSettersFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "abstract class SimpleComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " SimpleComponent build();",
+ " void set1(String s);",
+ " void set2(Integer s);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.extraSetters(),
+ "[void test.SimpleComponent.Builder.set1(String),"
+ + " void test.SimpleComponent.Builder.set2(Integer)]"))
+ .in(componentFile).onLine(10);
+
+ }
+
+ @Test
+ public void testMissingSettersFail() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " TestModule(String unused) {}",
+ " @Provides String s() { return null; }",
+ "}");
+ JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test2Module {",
+ " @Provides Integer i() { return null; }",
+ "}");
+ JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test3Module {",
+ " Test3Module(String unused) {}",
+ " @Provides Double d() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = {TestModule.class, Test2Module.class, Test3Module.class},",
+ " dependencies = OtherComponent.class)",
+ "interface TestComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Component.Builder",
+ " interface Builder {",
+ " TestComponent create();",
+ " }",
+ "}");
+ JavaFileObject otherComponent = JavaFileObjects.forSourceLines("test.OtherComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface OtherComponent {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile, module2File, module3File, componentFile, otherComponent))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ // Ignores Test2Module because we can construct it ourselves.
+ // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
+ String.format(MSGS.missingSetters(),
+ "[test.TestModule, test.Test3Module, test.OtherComponent]"))
+ .in(componentFile).onLine(12);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java
new file mode 100644
index 0000000..28e3b45
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java
@@ -0,0 +1,2185 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.writer.StringLiteral;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT;
+import static javax.tools.StandardLocation.SOURCE_OUTPUT;
+
+@RunWith(JUnit4.class)
+public class ComponentProcessorTest {
+ private static final StringLiteral NPE_LITERAL =
+ StringLiteral.forValue(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD);
+
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "final class NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnEnum() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "enum NotAComponent {",
+ " INSTANCE",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnAnnotation() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "@interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void nonModuleModule() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = Object.class)",
+ "interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("is not annotated with @Module");
+ }
+
+ private void checkCannotReferToModuleOfType(String moduleType) {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ moduleType + " TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface BadComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT, "test.TestModule"));
+ }
+
+ @Test public void cannotReferToAbstractClassModules() {
+ checkCannotReferToModuleOfType("abstract class");
+ }
+
+ @Test public void cannotReferToInterfaceModules() {
+ checkCannotReferToModuleOfType("interface");
+ }
+
+ @Test public void doubleBindingFromResolvedModules() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "abstract class ParentModule<A> {",
+ " @Provides List<A> provideListB(A a) { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildNumberModule extends ParentModule<Integer> {",
+ " @Provides Integer provideInteger() { return null; }",
+ "}");
+ JavaFileObject another = JavaFileObjects.forSourceLines("test.AnotherModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "class AnotherModule {",
+ " @Provides List<Integer> provideListOfInteger() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.List;",
+ "",
+ "@Component(modules = {ChildNumberModule.class, AnotherModule.class})",
+ "interface BadComponent {",
+ " List<Integer> listOfInteger();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child, another, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile().withErrorContaining(
+ "java.util.List<java.lang.Integer> is bound multiple times")
+ .and().withErrorContaining(
+ "@Provides List<Integer> test.ChildNumberModule.provideListB(Integer)")
+ .and().withErrorContaining(
+ "@Provides List<Integer> test.AnotherModule.provideListOfInteger()");
+ }
+
+ @Test public void simpleComponent() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ " Lazy<SomeInjectableType> lazySomeInjectableType();",
+ " Provider<SomeInjectableType> someInjectableTypeProvider();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheckLazy.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return SomeInjectableType_Factory.create();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentWithScope() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "import javax.inject.Provider;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ " Lazy<SomeInjectableType> lazySomeInjectableType();",
+ " Provider<SomeInjectableType> someInjectableTypeProvider();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import dagger.internal.ScopedProvider;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectableTypeProvider =",
+ " ScopedProvider.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Lazy<SomeInjectableType> lazySomeInjectableType() {",
+ " return DoubleCheckLazy.create(someInjectableTypeProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Provider<SomeInjectableType> someInjectableTypeProvider() {",
+ " return someInjectableTypeProvider;",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerOuterType_SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "import test.OuterType.SimpleComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerOuterType_SimpleComponent implements SimpleComponent {",
+ " private MembersInjector<B> bMembersInjector;",
+ "",
+ " private DaggerOuterType_SimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.bMembersInjector =",
+ " OuterType$B_MembersInjector.create(OuterType$A_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return OuterType$A_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public void inject(B b) {",
+ " bMembersInjector.injectMembers(b);",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerOuterType_SimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentWithModule() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(B b) {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "interface B {}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class C {",
+ " @Inject C() {}",
+ "}");
+
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides B b(C c) { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<B> bProvider;",
+ " private Provider<A> aProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.bProvider = TestModule_BFactory.create(builder.testModule,",
+ " C_Factory.create());",
+ " this.aProvider = A_Factory.create(bProvider);",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private TestModule testModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (testModule == null) {",
+ " this.testModule = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, cFile, moduleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void transitiveModuleDeps() {
+ JavaFileObject always = JavaFileObjects.forSourceLines("test.AlwaysIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class AlwaysIncluded {}");
+ JavaFileObject testModule = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {DepModule.class, AlwaysIncluded.class})",
+ "final class TestModule extends ParentTestModule {}");
+ JavaFileObject parentTest = JavaFileObjects.forSourceLines("test.ParentTestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})",
+ "class ParentTestModule {}");
+ JavaFileObject parentTestIncluded = JavaFileObjects.forSourceLines("test.ParentTestIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class ParentTestIncluded {}");
+ JavaFileObject depModule = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {RefByDep.class, AlwaysIncluded.class})",
+ "final class DepModule extends ParentDepModule {}");
+ JavaFileObject refByDep = JavaFileObjects.forSourceLines("test.RefByDep",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class RefByDep extends ParentDepModule {}");
+ JavaFileObject parentDep = JavaFileObjects.forSourceLines("test.ParentDepModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})",
+ "class ParentDepModule {}");
+ JavaFileObject parentDepIncluded = JavaFileObjects.forSourceLines("test.ParentDepIncluded",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AlwaysIncluded.class)",
+ "final class ParentDepIncluded {}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ "}");
+ // Generated code includes all includes, but excludes the parent modules.
+ // The "always" module should only be listed once.
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder parentTestIncluded(ParentTestIncluded parentTestIncluded) {",
+ " if (parentTestIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder alwaysIncluded(AlwaysIncluded alwaysIncluded) {",
+ " if (alwaysIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder depModule(DepModule depModule) {",
+ " if (depModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder parentDepIncluded(ParentDepIncluded parentDepIncluded) {",
+ " if (parentDepIncluded == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ "",
+ " @Deprecated",
+ " public Builder refByDep(RefByDep refByDep) {",
+ " if (refByDep == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(always,
+ testModule,
+ parentTest,
+ parentTestIncluded,
+ depModule,
+ refByDep,
+ parentDep,
+ parentDepIncluded,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void generatedTransitiveModule() {
+ JavaFileObject rootModule = JavaFileObjects.forSourceLines("test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = GeneratedModule.class)",
+ "final class RootModule {}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface TestComponent {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(rootModule, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile();
+ assertAbout(javaSources())
+ .that(ImmutableList.of(rootModule, component))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class GeneratedModule {}"))
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void generatedModuleInSubcomponent() {
+ JavaFileObject subcomponent =
+ JavaFileObjects.forSourceLines(
+ "test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GeneratedModule.class)",
+ "interface ChildComponent {}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent childComponent();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(subcomponent, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile();
+ assertAbout(javaSources())
+ .that(ImmutableList.of(subcomponent, component))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class GeneratedModule {}"))
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void subcomponentOmitsInheritedBindings() {
+ JavaFileObject parent =
+ JavaFileObjects.forSourceLines(
+ "test.Parent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = ParentModule.class)",
+ "interface Parent {",
+ " Child child();",
+ "}");
+ JavaFileObject parentModule =
+ JavaFileObjects.forSourceLines(
+ "test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.mapkeys.StringKey;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "@Module",
+ "class ParentModule {",
+ " @Provides(type = SET) static Object parentObject() {",
+ " return \"parent object\";",
+ " }",
+ "",
+ " @Provides(type = MAP) @StringKey(\"parent key\") Object parentKeyObject() {",
+ " return \"parent value\";",
+ " }",
+ "}");
+ JavaFileObject child =
+ JavaFileObjects.forSourceLines(
+ "test.Child",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent",
+ "interface Child {",
+ " Set<Object> objectSet();",
+ " Map<String, Object> objectMap();",
+ "}");
+ JavaFileObject expected =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerParent",
+ "package test;",
+ "",
+ "import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerParent implements Parent {",
+ " private Provider<Set<Object>> setOfObjectContribution1Provider;",
+ " private Provider<Set<Object>> setOfObjectProvider;",
+ " private Provider<Object> mapOfStringAndProviderOfObjectContribution1;",
+ " private Provider<Map<String, Provider<Object>>>",
+ " mapOfStringAndProviderOfObjectProvider;",
+ "",
+ " private DaggerParent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Parent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.setOfObjectContribution1Provider =",
+ " ParentModule_ParentObjectFactory.create();",
+ " this.setOfObjectProvider = SetFactory.create(setOfObjectContribution1Provider);",
+ " this.mapOfStringAndProviderOfObjectContribution1 =",
+ " ParentModule_ParentKeyObjectFactory.create(builder.parentModule);",
+ " this.mapOfStringAndProviderOfObjectProvider =",
+ " MapProviderFactory.<String, Object>builder(1)",
+ " .put(\"parent key\", mapOfStringAndProviderOfObjectContribution1)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Child child() {",
+ " return new ChildImpl();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private ParentModule parentModule;",
+ "",
+ " private Builder() {}",
+ "",
+ " public Parent build() {",
+ " if (parentModule == null) {",
+ " this.parentModule = new ParentModule();",
+ " }",
+ " return new DaggerParent(this);",
+ " }",
+ "",
+ " public Builder parentModule(ParentModule parentModule) {",
+ " if (parentModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.parentModule = parentModule;",
+ " return this;",
+ " }",
+ " }",
+ "",
+ " private final class ChildImpl implements Child {",
+ " private Provider<Map<String, Object>> mapOfStringAndObjectProvider;",
+ "",
+ " private ChildImpl() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.mapOfStringAndObjectProvider = MapFactory.create(",
+ " DaggerParent.this.mapOfStringAndProviderOfObjectProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Set<Object> objectSet() {",
+ " return DaggerParent.this.setOfObjectProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Map<String, Object> objectMap() {",
+ " return mapOfStringAndObjectProvider.get();",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(parent, parentModule, child))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void testDefaultPackage() {
+ JavaFileObject aClass = JavaFileObjects.forSourceLines("AClass", "class AClass {}");
+ JavaFileObject bClass = JavaFileObjects.forSourceLines("BClass",
+ "import javax.inject.Inject;",
+ "",
+ "class BClass {",
+ " @Inject BClass(AClass a) {}",
+ "}");
+ JavaFileObject aModule = JavaFileObjects.forSourceLines("AModule",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module class AModule {",
+ " @Provides AClass aClass() {",
+ " return new AClass();",
+ " }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("SomeComponent",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = AModule.class)",
+ "interface SomeComponent {",
+ " BClass bClass();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aModule, aClass, bClass, component))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void setBindings() {
+ JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Collections;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class EmptySetModule {",
+ " @Provides(type = SET_VALUES) Set<String> emptySet() { return Collections.emptySet(); }",
+ "}");
+ JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class SetModule {",
+ " @Provides(type = SET) String string() { return \"\"; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {EmptySetModule.class, SetModule.class})",
+ "interface TestComponent {",
+ " Set<String> strings();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Set<String>> setOfStringContribution1Provider;",
+ " private Provider<Set<String>> setOfStringContribution2Provider;",
+ " private Provider<Set<String>> setOfStringProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.setOfStringContribution1Provider =",
+ " EmptySetModule_EmptySetFactory.create(builder.emptySetModule);",
+ " this.setOfStringContribution2Provider =",
+ " SetModule_StringFactory.create(builder.setModule);",
+ " this.setOfStringProvider = SetFactory.create(",
+ " setOfStringContribution1Provider, setOfStringContribution2Provider);",
+ " }",
+ "",
+ " @Override",
+ " public Set<String> strings() {",
+ " return setOfStringProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private EmptySetModule emptySetModule;",
+ " private SetModule setModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (emptySetModule == null) {",
+ " this.emptySetModule = new EmptySetModule();",
+ " }",
+ " if (setModule == null) {",
+ " this.setModule = new SetModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder emptySetModule(EmptySetModule emptySetModule) {",
+ " if (emptySetModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.emptySetModule = emptySetModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder setModule(SetModule setModule) {",
+ " if (setModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.setModule = setModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(emptySetModuleFile, setModuleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void membersInjection() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectedType {",
+ " @Inject SomeInjectableType injectedField;",
+ " SomeInjectedType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " void inject(SomeInjectedType instance);",
+ " SomeInjectedType injectAndReturn(SomeInjectedType instance);",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectedTypeMembersInjector =",
+ " SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public void inject(SomeInjectedType instance) {",
+ " someInjectedTypeMembersInjector.injectMembers(instance);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectedType injectAndReturn(SomeInjectedType instance) {",
+ " someInjectedTypeMembersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentInjection() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType(SimpleComponent component) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.internal.InstanceFactory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SimpleComponent> simpleComponentProvider;",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.simpleComponentProvider = InstanceFactory.<SimpleComponent>create(this);",
+ " this.someInjectableTypeProvider =",
+ " SomeInjectableType_Factory.create(simpleComponentProvider);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void membersInjectionInsideProvision() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectedType {",
+ " @Inject SomeInjectableType injectedField;",
+ " @Inject SomeInjectedType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectedType createAndInject();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private MembersInjector<SomeInjectedType> someInjectedTypeMembersInjector;",
+ " private Provider<SomeInjectedType> someInjectedTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectedTypeMembersInjector =",
+ " SomeInjectedType_MembersInjector.create(SomeInjectableType_Factory.create());",
+ " this.someInjectedTypeProvider =",
+ " SomeInjectedType_Factory.create(someInjectedTypeMembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectedType createAndInject() {",
+ " return someInjectedTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, injectedTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void injectionWithGenericBaseClass() {
+ JavaFileObject genericType = JavaFileObjects.forSourceLines("test.AbstractGenericType",
+ "package test;",
+ "",
+ "abstract class AbstractGenericType<T> {",
+ "}");
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType extends AbstractGenericType<String> {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.MembersInjectors;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<SomeInjectableType> someInjectableTypeProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.someInjectableTypeProvider =",
+ " SomeInjectableType_Factory.create((MembersInjector) MembersInjectors.noOp());",
+ " }",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return someInjectableTypeProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(genericType, injectableTypeFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void componentDependency() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class B {",
+ " @Inject B(A a) {}",
+ "}");
+ JavaFileObject aComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface AComponent {",
+ " A a();",
+ "}");
+ JavaFileObject bComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(dependencies = AComponent.class)",
+ "interface BComponent {",
+ " B b();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerBComponent",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerBComponent implements BComponent {",
+ " private Provider<A> aProvider;",
+ " private Provider<B> bProvider;",
+ "",
+ " private DaggerBComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.aProvider = new Factory<A>() {",
+ " private final AComponent aComponent = builder.aComponent;",
+ " @Override public A get() {",
+ " A provided = aComponent.a();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ " };",
+ " this.bProvider = B_Factory.create(aProvider);",
+ " }",
+ "",
+ " @Override",
+ " public B b() {",
+ " return bProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private AComponent aComponent;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public BComponent build() {",
+ " if (aComponent == null) {",
+ " throw new IllegalStateException(AComponent.class.getCanonicalName()",
+ " + \" must be set\");",
+ " }",
+ " return new DaggerBComponent(this);",
+ " }",
+ "",
+ " public Builder aComponent(AComponent aComponent) {",
+ " if (aComponent == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.aComponent = aComponent;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, aComponentFile, bComponentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void moduleNameCollision() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "public final class A {}");
+ JavaFileObject otherAFile = JavaFileObjects.forSourceLines("other.test.A",
+ "package other.test;",
+ "",
+ "public final class A {}");
+
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "public final class TestModule {",
+ " @Provides A a() { return null; }",
+ "}");
+ JavaFileObject otherModuleFile = JavaFileObjects.forSourceLines("other.test.TestModule",
+ "package other.test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "public final class TestModule {",
+ " @Provides A a() { return null; }",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {TestModule.class, other.test.TestModule.class})",
+ "interface TestComponent {",
+ " A a();",
+ " other.test.A otherA();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.test.A;",
+ "import other.test.TestModule;",
+ "import other.test.TestModule_AFactory;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<test.A> aProvider;",
+ " private Provider<A> aProvider1;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.aProvider = test.TestModule_AFactory.create(builder.testModule);",
+ " this.aProvider1 = TestModule_AFactory.create(builder.testModule1);",
+ " }",
+ "",
+ " @Override",
+ " public test.A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public A otherA() {",
+ " return aProvider1.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private test.TestModule testModule;",
+ " private TestModule testModule1;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (testModule == null) {",
+ " this.testModule = new test.TestModule();",
+ " }",
+ " if (testModule1 == null) {",
+ " this.testModule1 = new TestModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder testModule(test.TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule = testModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder testModule(TestModule testModule) {",
+ " if (testModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testModule1 = testModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, otherAFile, moduleFile, otherModuleFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void resolutionOrder() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(B b) {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class B {",
+ " @Inject B(C c) {}",
+ "}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class C {",
+ " @Inject C() {}",
+ "}");
+ JavaFileObject xFile = JavaFileObjects.forSourceLines("test.X",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class X {",
+ " @Inject X(C c) {}",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " A a();",
+ " C c();",
+ " X x();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<B> bProvider;",
+ " private Provider<A> aProvider;",
+ " private Provider<X> xProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.bProvider = B_Factory.create(C_Factory.create());",
+ " this.aProvider = A_Factory.create(bProvider);",
+ " this.xProvider = X_Factory.create(C_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public A a() {",
+ " return aProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public C c() {",
+ " return C_Factory.create().get();",
+ " }",
+ "",
+ " @Override",
+ " public X x() {",
+ " return xProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile, cFile, xFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponent_redundantComponentMethod() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentSupertypeAFile = JavaFileObjects.forSourceLines("test.SupertypeA",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SupertypeA {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject componentSupertypeBFile = JavaFileObjects.forSourceLines("test.SupertypeB",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SupertypeB {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends SupertypeA, SupertypeB {",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {}",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(
+ injectableTypeFile, componentSupertypeAFile, componentSupertypeBFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void simpleComponent_inheritedComponentMethodDep() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType() {}",
+ "}");
+ JavaFileObject componentSupertype = JavaFileObjects.forSourceLines("test.Supertype",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface Supertype {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject depComponentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends Supertype {",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ComponentWithDep",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(dependencies = SimpleComponent.class)",
+ "interface ComponentWithDep {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {}",
+ "",
+ " @Override",
+ " public SomeInjectableType someInjectableType() {",
+ " return SomeInjectableType_Factory.create().get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(
+ injectableTypeFile, componentSupertype, depComponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void wildcardGenericsRequiresAtProvides() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class B<T> {",
+ " @Inject B(T t) {}",
+ "}");
+ JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class C {",
+ " @Inject C(B<? extends A> bA) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " C c();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, cFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.B<? extends test.A> cannot be provided without an @Provides-annotated method");
+ }
+ @Test
+ public void componentImplicitlyDependsOnGeneratedType() {
+ JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SomeInjectableType {",
+ " @Inject SomeInjectableType(GeneratedType generatedType) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " SomeInjectableType someInjectableType();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(injectableTypeFile, componentFile))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"))
+ .compilesWithoutError()
+ .and()
+ .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
+ }
+ @Test
+ public void componentSupertypeDependsOnGeneratedType() {
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent extends SimpleComponentInterface {}");
+ JavaFileObject interfaceFile =
+ JavaFileObjects.forSourceLines(
+ "test.SimpleComponentInterface",
+ "package test;",
+ "",
+ "interface SimpleComponentInterface {",
+ " GeneratedType generatedType();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(componentFile, interfaceFile))
+ .processedWith(
+ new ComponentProcessor(),
+ new GeneratingProcessor(
+ "test.GeneratedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"))
+ .compilesWithoutError()
+ .and()
+ .generatesFileNamed(SOURCE_OUTPUT, "test", "DaggerSimpleComponent.java");
+ }
+
+ @Test
+ @Ignore // modify this test as necessary while debugging for your situation.
+ @SuppressWarnings("unused")
+ public void genericTestToLetMeDebugInEclipse() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "public class B<T> {",
+ " @Inject B() {}",
+ "}");
+ JavaFileObject dFile = JavaFileObjects.forSourceLines("test.sub.D",
+ "package test.sub;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "import test.B;",
+ "",
+ "public class D {",
+ " @Inject D(B<A.InA> ba) {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Lazy;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " B<A> d();",
+ " Provider<B<A>> d2();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerSimpleComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerSimpleComponent implements SimpleComponent {",
+ " private Provider<D> dProvider;",
+ "",
+ " private DaggerSimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static SimpleComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.dProvider = new D_Factory(B_Factory.INSTANCE);",
+ " }",
+ "",
+ " @Override",
+ " public D d() {",
+ " return dProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " return new DaggerSimpleComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ /**
+ * A simple {@link Processor} that generates one source file.
+ */
+ private static final class GeneratingProcessor extends AbstractProcessor {
+ private final String generatedClassName;
+ private final String generatedSource;
+ private boolean processed;
+
+ GeneratingProcessor(String generatedClassName, String... source) {
+ this.generatedClassName = generatedClassName;
+ this.generatedSource = Joiner.on("\n").join(source);
+ }
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!processed) {
+ processed = true;
+ try (Writer writer =
+ processingEnv.getFiler().createSourceFile(generatedClassName).openWriter()) {
+ writer.append(generatedSource);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java
new file mode 100644
index 0000000..b47a43c
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.List;
+import javax.inject.Provider;
+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 javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Test case for {@link DependencyRequestMapper}.
+ */
+@RunWith(JUnit4.class)
+public class DependencyRequestMapperTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+ private DependencyRequest.Factory dependencyRequestFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ this.dependencyRequestFactory = new DependencyRequest.Factory(elements, keyFactory);
+ }
+
+ private List<? extends VariableElement> sampleProviderParameters() {
+ TypeElement moduleElement =
+ elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ return providesMethod.getParameters();
+ }
+
+ private List<? extends VariableElement> sampleProducerParameters() {
+ TypeElement moduleElement =
+ elements.getTypeElement(ProducesMethodModule.class.getCanonicalName());
+ ExecutableElement producesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ return producesMethod.getParameters();
+ }
+
+ private DependencyRequest dependencyRequestForInstance() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(0));
+ }
+
+ private DependencyRequest dependencyRequestForLazy() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(1));
+ }
+
+ private DependencyRequest dependencyRequestForProvider() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(2));
+ }
+
+ private DependencyRequest dependencyRequestForMembersInjector() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProviderParameters().get(3));
+ }
+
+ private DependencyRequest dependencyRequestForProducer() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProducerParameters().get(0));
+ }
+
+ private DependencyRequest dependencyRequestForProduced() {
+ return dependencyRequestFactory.forRequiredVariable(sampleProducerParameters().get(1));
+ }
+
+ @Test public void forProvider() {
+ DependencyRequestMapper mapper = DependencyRequestMapper.FOR_PROVIDER;
+ assertThat(mapper.getFrameworkClass(dependencyRequestForInstance()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForLazy()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProvider()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForMembersInjector()))
+ .isEqualTo(MembersInjector.class);
+ }
+
+ @Test public void forProducer() {
+ DependencyRequestMapper mapper = DependencyRequestMapper.FOR_PRODUCER;
+ assertThat(mapper.getFrameworkClass(dependencyRequestForInstance()))
+ .isEqualTo(Producer.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForLazy()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProvider()))
+ .isEqualTo(Provider.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForMembersInjector()))
+ .isEqualTo(MembersInjector.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProducer()))
+ .isEqualTo(Producer.class);
+ assertThat(mapper.getFrameworkClass(dependencyRequestForProduced()))
+ .isEqualTo(Producer.class);
+ }
+
+ @Module
+ static final class ProvidesMethodModule {
+ @Provides String provideString(
+ Integer a, Lazy<Integer> b, Provider<Integer> c, MembersInjector<Y> d) {
+ return null;
+ }
+ }
+
+ @ProducerModule
+ static final class ProducesMethodModule {
+ @Produces String produceString(Producer<Integer> a, Produced<Integer> b) {
+ return null;
+ }
+ }
+
+ static final class Y {}
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java b/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java
new file mode 100644
index 0000000..141d5c4
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ErrorMessagesTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class ErrorMessagesTest {
+ @Test public void stripCommonTypePrefixes() {
+ String typeName = "com.google.common.collect.ImmutableList<java.lang.Boolean>";
+ assertThat(ErrorMessages.stripCommonTypePrefixes(typeName)).isEqualTo("ImmutableList<Boolean>");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java b/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java
new file mode 100644
index 0000000..e207fe0
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/GraphValidationScopingTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+@RunWith(JUnit4.class)
+public class GraphValidationScopingTest {
+ @Test public void componentWithoutScopeIncludesScopedBindings_Fail() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component(modules = ScopedModule.class)",
+ "interface MyComponent {",
+ " ScopedType string();",
+ "}");
+ JavaFileObject typeFile = JavaFileObjects.forSourceLines("test.ScopedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "class ScopedType {",
+ " @Inject ScopedType(String s, long l, float f) {}",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ScopedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "class ScopedModule {",
+ " @Provides @Singleton String string() { return \"a string\"; }",
+ " @Provides long integer() { return 0L; }",
+ " @Provides float floatingPoint() { return 0.0f; }",
+ "}");
+ String errorMessage = "test.MyComponent (unscoped) may not reference scoped bindings:\n"
+ + " @Provides @Singleton String test.ScopedModule.string()\n"
+ + " @Singleton class test.ScopedType";
+ assert_().about(javaSources()).that(asList(componentFile, typeFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithScopeIncludesIncompatiblyScopedBindings_Fail() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(modules = ScopedModule.class)",
+ "interface MyComponent {",
+ " ScopedType string();",
+ "}");
+ JavaFileObject scopeFile = JavaFileObjects.forSourceLines("test.PerTest",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "@interface PerTest {}");
+ JavaFileObject typeFile = JavaFileObjects.forSourceLines("test.ScopedType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@PerTest", // incompatible scope
+ "class ScopedType {",
+ " @Inject ScopedType(String s, long l, float f) {}",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ScopedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "class ScopedModule {",
+ " @Provides @PerTest String string() { return \"a string\"; }", // incompatible scope
+ " @Provides long integer() { return 0L; }", // unscoped - valid
+ " @Provides @Singleton float floatingPoint() { return 0.0f; }", // same scope - valid
+ "}");
+ String errorMessage = "test.MyComponent scoped with @Singleton "
+ + "may not reference bindings with different scopes:\n"
+ + " @Provides @test.PerTest String test.ScopedModule.string()\n"
+ + " @test.PerTest class test.ScopedType";
+ assert_().about(javaSources()).that(asList(componentFile, scopeFile, typeFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test 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",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ " static class A { @Inject A() {} }",
+ " static class B { @Inject B() {} }",
+ "}");
+ JavaFileObject simpleScope = JavaFileObjects.forSourceLines("test.SimpleScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface SimpleScope {}");
+ JavaFileObject singletonScopedA = JavaFileObjects.forSourceLines("test.SingletonComponentA",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SingletonComponentA {",
+ " SimpleType.A type();",
+ "}");
+ JavaFileObject singletonScopedB = JavaFileObjects.forSourceLines("test.SingletonComponentB",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface SingletonComponentB {",
+ " SimpleType.B type();",
+ "}");
+ JavaFileObject scopeless = JavaFileObjects.forSourceLines("test.ScopelessComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface ScopelessComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject simpleScoped = JavaFileObjects.forSourceLines("test.SimpleScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@SimpleScope",
+ "@Component(dependencies = {SingletonComponentA.class, SingletonComponentB.class})",
+ "interface SimpleScopedComponent {",
+ " SimpleType.A type();",
+ "}");
+ String errorMessage =
+ "@test.SimpleScope test.SimpleScopedComponent depends on more than one scoped component:\n"
+ + " @Singleton test.SingletonComponentA\n"
+ + " @Singleton test.SingletonComponentB";
+ assert_().about(javaSources())
+ .that(
+ asList(type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithoutScopeCannotDependOnScopedComponent() {
+ JavaFileObject type = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject scopedComponent = JavaFileObjects.forSourceLines("test.ScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component",
+ "interface ScopedComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject unscopedComponent = JavaFileObjects.forSourceLines("test.UnscopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component(dependencies = ScopedComponent.class)",
+ "interface UnscopedComponent {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "test.UnscopedComponent (unscoped) cannot depend on scoped components:\n"
+ + " @Singleton test.ScopedComponent";
+ assert_().about(javaSources())
+ .that(asList(type, scopedComponent, unscopedComponent))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentWithSingletonScopeMayNotDependOnOtherScope() {
+ // Singleton must be the widest lifetime of present scopes.
+ 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 simpleScoped = JavaFileObjects.forSourceLines("test.SimpleScopedComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@SimpleScope",
+ "@Component",
+ "interface SimpleScopedComponent {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject singletonScoped = JavaFileObjects.forSourceLines("test.SingletonComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Singleton",
+ "@Component(dependencies = SimpleScopedComponent.class)",
+ "interface SingletonComponent {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "This @Singleton component cannot depend on scoped components:\n"
+ + " @test.SimpleScope test.SimpleScopedComponent";
+ assert_().about(javaSources())
+ .that(asList(type, simpleScope, simpleScoped, singletonScoped))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @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
+ // scopes on components such that they cycle.
+ 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 mediumLifetime = JavaFileObjects.forSourceLines("test.ComponentMedium",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@ScopeB",
+ "@Component(dependencies = ComponentLong.class)",
+ "interface ComponentMedium {",
+ " SimpleType type();",
+ "}");
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@ScopeA",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentShort {",
+ " SimpleType type();",
+ "}");
+ String errorMessage =
+ "test.ComponentShort depends on scoped components in a non-hierarchical scope ordering:\n"
+ + " @test.ScopeA test.ComponentLong\n"
+ + " @test.ScopeB test.ComponentMedium\n"
+ + " @test.ScopeA test.ComponentShort";
+ assert_().about(javaSources())
+ .that(asList(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java
new file mode 100644
index 0000000..6001ea7
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/GraphValidationTest.java
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import java.util.Arrays;
+import javax.tools.JavaFileObject;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.nullableToNonNullable;
+
+@RunWith(JUnit4.class)
+public class GraphValidationTest {
+ private final JavaFileObject NULLABLE = JavaFileObjects.forSourceLines("test.Nullable",
+ "package test;",
+ "public @interface Nullable {}");
+
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject injectable = JavaFileObjects.forSourceLines("test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Foo {",
+ " @Inject Foo(Bar bar) {}",
+ "}");
+ JavaFileObject nonInjectable = JavaFileObjects.forSourceLines("test.Bar",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "interface Bar {}");
+ assertAbout(javaSources()).that(Arrays.asList(component, injectable, nonInjectable))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("test.Bar cannot be provided without an @Provides-annotated method.")
+ .in(component).onLine(7);
+ }
+
+ @Test public void componentProvisionWithNoDependencyChain() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Qualifier;",
+ "",
+ "final class TestClass {",
+ " @Qualifier @interface Q {}",
+ " interface A {}",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " A getA();",
+ " @Q A qualifiedA();",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.")
+ .in(component)
+ .onLine(12)
+ .and()
+ .withErrorContaining(
+ "@test.TestClass.Q test.TestClass.A "
+ + "cannot be provided without an @Provides-annotated method.")
+ .in(component)
+ .onLine(13);
+ }
+
+ @Test public void constructorInjectionWithoutAnnotation() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static class A {",
+ " A() {}",
+ " }",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " A getA();",
+ " }",
+ "}");
+ String expectedError = "test.TestClass.A cannot be provided without an "
+ + "@Inject constructor or from an @Provides-annotated method.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(15);
+ }
+
+ @Test public void membersInjectWithoutProvision() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ "",
+ " @Component()",
+ " interface AComponent {",
+ " B getB();",
+ " }",
+ "}");
+ String expectedError = "test.TestClass.B cannot be provided without an "
+ + "@Inject constructor or from an @Provides-annotated method. "
+ + "This type supports members injection but cannot be implicitly provided.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(19);
+ }
+
+ @Test public void cyclicDependency() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface CComponent {",
+ " C getC();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.CComponent.getC() contains a dependency cycle:\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(23);
+ }
+
+ @Test public void cyclicDependencyNotIncludingEntryPoint() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D(C cParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface DComponent {",
+ " D getD();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.DComponent.getD() contains a dependency cycle:\n"
+ + " test.Outer.D.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(27);
+ }
+
+ @Test
+ public void cyclicDependencyNotBrokenByMapBinding() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.MapKey;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Map;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(Map<String, C> cMap) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " @Component(modules = CModule.class)",
+ " interface CComponent {",
+ " C getC();",
+ " }",
+ "",
+ " @Module",
+ " static class CModule {",
+ " @Provides(type = Provides.Type.MAP)",
+ " @StringKey(\"C\")",
+ " static C c(C c) {",
+ " return c;",
+ " }",
+ " }",
+ "",
+ " @MapKey",
+ " @interface StringKey {",
+ " String value();",
+ " }",
+ "}");
+
+ String expectedError =
+ Joiner.on('\n')
+ .join(
+ "test.Outer.CComponent.getC() contains a dependency cycle:",
+ " test.Outer.C.<init>(test.Outer.B bParam)",
+ " [parameter: test.Outer.B bParam]",
+ " test.Outer.B.<init>(test.Outer.A aParam)",
+ " [parameter: test.Outer.A aParam]",
+ " test.Outer.A.<init>(java.util.Map<java.lang.String,test.Outer.C> cMap)",
+ " [parameter: java.util.Map<java.lang.String,test.Outer.C> cMap]",
+ " test.Outer.A.<init>(java.util.Map<java.lang.String,test.Outer.C> cMap)",
+ " [parameter: java.util.Map<java.lang.String,test.Outer.C> cMap]",
+ " test.Outer.CModule.c(test.Outer.C c)",
+ " [parameter: test.Outer.C c]");
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(25);
+ }
+
+ @Test
+ public void falsePositiveCyclicDependencyIndirectionDetected() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(C cParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(A aParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(B bParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D(Provider<C> cParam) {}",
+ " }",
+ "",
+ " @Component()",
+ " interface DComponent {",
+ " D getD();",
+ " }",
+ "}");
+
+ String expectedError =
+ "test.Outer.DComponent.getD() contains a dependency cycle:\n"
+ + " test.Outer.D.<init>(javax.inject.Provider<test.Outer.C> cParam)\n"
+ + " [parameter: javax.inject.Provider<test.Outer.C> cParam]\n"
+ + " test.Outer.C.<init>(test.Outer.B bParam)\n"
+ + " [parameter: test.Outer.B bParam]\n"
+ + " test.Outer.B.<init>(test.Outer.A aParam)\n"
+ + " [parameter: test.Outer.A aParam]\n"
+ + " test.Outer.A.<init>(test.Outer.C cParam)\n"
+ + " [parameter: test.Outer.C cParam]";
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(28);
+ }
+
+ @Ignore @Test public void cyclicDependencySimpleProviderIndirectionWarning() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(B bParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(C bParam, D dParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(Provider<A> aParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D() {}",
+ " }",
+ "",
+ " @Component()",
+ " interface CComponent {",
+ " C get();",
+ " }",
+ "}");
+
+ /* String expectedWarning =
+ "test.Outer.CComponent.get() contains a dependency cycle:"
+ + " test.Outer.C.<init>(javax.inject.Provider<test.Outer.A> aParam)"
+ + " [parameter: javax.inject.Provider<test.Outer.A> aParam]"
+ + " test.Outer.A.<init>(test.Outer.B bParam)"
+ + " [parameter: test.Outer.B bParam]"
+ + " test.Outer.B.<init>(test.Outer.C bParam, test.Outer.D dParam)"
+ + " [parameter: test.Outer.C bParam]";
+ */
+ assertAbout(javaSource()) // TODO(cgruber): Implement warning checks.
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ //.withWarningContaining(expectedWarning).in(component).onLine(X);
+ }
+
+ @Ignore @Test public void cyclicDependencySimpleProviderIndirectionWarningSuppressed() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Outer {",
+ " static class A {",
+ " @Inject A(B bParam) {}",
+ " }",
+ "",
+ " static class B {",
+ " @Inject B(C bParam, D dParam) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject C(Provider<A> aParam) {}",
+ " }",
+ "",
+ " static class D {",
+ " @Inject D() {}",
+ " }",
+ "",
+ " @SuppressWarnings(\"dependency-cycle\")",
+ " @Component()",
+ " interface CComponent {",
+ " C get();",
+ " }",
+ "}");
+
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ //.compilesWithoutWarning(); //TODO(cgruber)
+ }
+
+ @Test public void duplicateExplicitBindings_ProvidesAndComponentProvision() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " interface B {}",
+ "",
+ " @Module",
+ " static class AModule {",
+ " @Provides String provideString() { return \"\"; }",
+ " @Provides A provideA(String s) { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = AModule.class)",
+ " interface Parent {",
+ " A getA();",
+ " }",
+ "",
+ " @Module",
+ " static class BModule {",
+ " @Provides B provideB(A a) { return new B() {}; }",
+ " }",
+ "",
+ " @Component(dependencies = Parent.class, modules = { BModule.class, AModule.class})",
+ " interface Child {",
+ " B getB();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " test.Outer.A test.Outer.Parent.getA()\n"
+ + " @Provides test.Outer.A test.Outer.AModule.provideA(String)";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(30);
+ }
+
+ @Test public void duplicateExplicitBindings_TwoProvidesMethods() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " @Module",
+ " static class Module1 {",
+ " @Provides A provideA1() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module2 {",
+ " @Provides String provideString() { return \"\"; }",
+ " @Provides A provideA2(String s) { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = { Module1.class, Module2.class})",
+ " interface TestComponent {",
+ " A getA();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " @Provides test.Outer.A test.Outer.Module1.provideA1()\n"
+ + " @Provides test.Outer.A test.Outer.Module2.provideA2(String)";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(24);
+ }
+
+ @Test public void duplicateExplicitBindings_MultipleProvisionTypes() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.MapKey;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.MapKey;",
+ "import java.util.HashMap;",
+ "import java.util.HashSet;",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "import static dagger.Provides.Type.MAP;",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "final class Outer {",
+ " @MapKey(unwrapValue = true)",
+ " @interface StringKey {",
+ " String value();",
+ " }",
+ "",
+ " @Module",
+ " static class TestModule1 {",
+ " @Provides(type = MAP)",
+ " @StringKey(\"foo\")",
+ " String stringMapEntry() { return \"\"; }",
+ "",
+ " @Provides(type = SET) String stringSetElement() { return \"\"; }",
+ " }",
+ "",
+ " @Module",
+ " static class TestModule2 {",
+ " @Provides Set<String> stringSet() { return new HashSet<String>(); }",
+ "",
+ " @Provides Map<String, String> stringMap() {",
+ " return new HashMap<String, String>();",
+ " }",
+ " }",
+ "",
+ " @Component(modules = { TestModule1.class, TestModule2.class })",
+ " interface TestComponent {",
+ " Set<String> getStringSet();",
+ " Map<String, String> getStringMap();",
+ " }",
+ "}");
+
+ String expectedSetError =
+ "java.util.Set<java.lang.String> has incompatible bindings:\n"
+ + " Set bindings:\n"
+ + " @Provides(type=SET) String test.Outer.TestModule1.stringSetElement()\n"
+ + " Unique bindings:\n"
+ + " @Provides Set<String> test.Outer.TestModule2.stringSet()";
+
+ String expectedMapError =
+ "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings:\n"
+ + " Map bindings:\n"
+ + " @Provides(type=MAP) @test.Outer.StringKey(\"foo\") String"
+ + " test.Outer.TestModule1.stringMapEntry()\n"
+ + " Unique bindings:\n"
+ + " @Provides Map<String,String> test.Outer.TestModule2.stringMap()";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedSetError).in(component).onLine(43)
+ .and().withErrorContaining(expectedMapError).in(component).onLine(44);
+ }
+
+ @Test public void duplicateBindings_TruncateAfterLimit() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class Outer {",
+ " interface A {}",
+ "",
+ " @Module",
+ " static class Module1 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module2 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module3 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module4 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module5 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module6 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module7 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module8 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module9 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module10 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module11 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Module",
+ " static class Module12 {",
+ " @Provides A provideA() { return new A() {}; }",
+ " }",
+ "",
+ " @Component(modules = {",
+ " Module1.class,",
+ " Module2.class,",
+ " Module3.class,",
+ " Module4.class,",
+ " Module5.class,",
+ " Module6.class,",
+ " Module7.class,",
+ " Module8.class,",
+ " Module9.class,",
+ " Module10.class,",
+ " Module11.class,",
+ " Module12.class",
+ " })",
+ " interface TestComponent {",
+ " A getA();",
+ " }",
+ "}");
+
+ String expectedError = "test.Outer.A is bound multiple times:\n"
+ + " @Provides test.Outer.A test.Outer.Module1.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module2.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module3.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module4.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module5.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module6.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module7.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module8.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module9.provideA()\n"
+ + " @Provides test.Outer.A test.Outer.Module10.provideA()\n"
+ + " and 2 others";
+
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(86);
+ }
+
+ @Test public void longChainOfDependencies() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " static class B {",
+ " @Inject B(A a) {}",
+ " }",
+ "",
+ " static class C {",
+ " @Inject B b;",
+ " @Inject C(B b) {}",
+ " }",
+ "",
+ " interface D { }",
+ "",
+ " static class DImpl implements D {",
+ " @Inject DImpl(C c, B b) {}",
+ " }",
+ "",
+ " @Module",
+ " static class DModule {",
+ " @Provides D d(DImpl impl) { return impl; }",
+ " }",
+ "",
+ " @Component(modules = { DModule.class })",
+ " interface AComponent {",
+ " D getFoo();",
+ " C injectC(C c);",
+ " }",
+ "}");
+ String errorText =
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.\n";
+ String firstError = errorText
+ + " test.TestClass.DModule.d(test.TestClass.DImpl impl)\n"
+ + " [parameter: test.TestClass.DImpl impl]\n"
+ + " test.TestClass.DImpl.<init>(test.TestClass.C c, test.TestClass.B b)\n"
+ + " [parameter: test.TestClass.C c]\n"
+ + " test.TestClass.C.b\n"
+ + " [injected field of type: test.TestClass.B b]\n"
+ + " test.TestClass.B.<init>(test.TestClass.A a)\n"
+ + " [parameter: test.TestClass.A a]";
+ String secondError = errorText
+ + " test.TestClass.C.b\n"
+ + " [injected field of type: test.TestClass.B b]\n"
+ + " test.TestClass.B.<init>(test.TestClass.A a)\n"
+ + " [parameter: test.TestClass.A a]";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(firstError).in(component).onLine(33)
+ .and().withErrorContaining(secondError).in(component).onLine(34);
+ }
+
+ @Test public void resolvedParametersInDependencyTrace() {
+ JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Generic<T> {",
+ " @Inject Generic(T t) {}",
+ "}");
+ JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "final class TestClass {",
+ " @Inject TestClass(List list) {}",
+ "}");
+ JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class UsesTest {",
+ " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " UsesTest usesTest();",
+ "}");
+ String expectedMsg = Joiner.on("\n").join(
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " test.UsesTest.<init>(test.Generic<test.TestClass> genericTestClass)",
+ " [parameter: test.Generic<test.TestClass> genericTestClass]",
+ " test.Generic.<init>(test.TestClass t)",
+ " [parameter: test.TestClass t]",
+ " test.TestClass.<init>(java.util.List list)",
+ " [parameter: java.util.List list]");
+ assertAbout(javaSources()).that(ImmutableList.of(generic, testClass, usesTest, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedMsg);
+ }
+
+ @Test public void resolvedVariablesInDependencyTrace() {
+ JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class Generic<T> {",
+ " @Inject T t;",
+ " @Inject Generic() {}",
+ "}");
+ JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "final class TestClass {",
+ " @Inject TestClass(List list) {}",
+ "}");
+ JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class UsesTest {",
+ " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " UsesTest usesTest();",
+ "}");
+ String expectedMsg = Joiner.on("\n").join(
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " test.UsesTest.<init>(test.Generic<test.TestClass> genericTestClass)",
+ " [parameter: test.Generic<test.TestClass> genericTestClass]",
+ " test.Generic.t",
+ " [injected field of type: test.TestClass t]",
+ " test.TestClass.<init>(java.util.List list)",
+ " [parameter: java.util.List list]");
+ assertAbout(javaSources()).that(ImmutableList.of(generic, testClass, usesTest, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedMsg);
+ }
+
+ @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();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @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();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @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();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, a, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @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();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ assertAbout(javaSources()).that(ImmutableList.of(NULLABLE, module, component))
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void componentDependencyMustNotCycle_Direct() {
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentShort.class)",
+ "interface ComponentShort {",
+ "}");
+ String errorMessage =
+ "test.ComponentShort contains a cycle in its component dependencies:\n"
+ + " test.ComponentShort";
+ assertAbout(javaSource())
+ .that(shortLifetime)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage);
+ }
+
+ @Test public void componentDependencyMustNotCycle_Indirect() {
+ JavaFileObject longLifetime = JavaFileObjects.forSourceLines("test.ComponentLong",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentLong {",
+ "}");
+ JavaFileObject mediumLifetime = JavaFileObjects.forSourceLines("test.ComponentMedium",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentLong.class)",
+ "interface ComponentMedium {",
+ "}");
+ JavaFileObject shortLifetime = JavaFileObjects.forSourceLines("test.ComponentShort",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(dependencies = ComponentMedium.class)",
+ "interface ComponentShort {",
+ "}");
+ String longErrorMessage =
+ "test.ComponentLong contains a cycle in its component dependencies:\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong";
+ String mediumErrorMessage =
+ "test.ComponentMedium contains a cycle in its component dependencies:\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium";
+ String shortErrorMessage =
+ "test.ComponentShort contains a cycle in its component dependencies:\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentLong\n"
+ + " test.ComponentMedium\n"
+ + " test.ComponentShort";
+ assertAbout(javaSources())
+ .that(ImmutableList.of(longLifetime, mediumLifetime, shortLifetime))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(longErrorMessage).in(longLifetime)
+ .and()
+ .withErrorContaining(mediumErrorMessage).in(mediumLifetime)
+ .and()
+ .withErrorContaining(shortErrorMessage).in(shortLifetime);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java b/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java
new file mode 100644
index 0000000..6355922
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/InaccessibleTypeTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class InaccessibleTypeTest {
+ @Test public void basicInjectedType() {
+ JavaFileObject noDepClassFile = JavaFileObjects.forSourceLines("foreign.NoDepClass",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class NoDepClass {",
+ " @Inject NoDepClass() {}",
+ "}");
+ JavaFileObject publicClassFile = JavaFileObjects.forSourceLines("foreign.PublicClass",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class PublicClass {",
+ " @Inject PublicClass(NonPublicClass1 dep1, NonPublicClass2 dep2, NoDepClass dep3) {}",
+ "}");
+ JavaFileObject nonPublicClass1File = JavaFileObjects.forSourceLines("foreign.NonPublicClass1",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NonPublicClass1 {",
+ " @Inject NonPublicClass1(NoDepClass dep) {}",
+ "}");
+ JavaFileObject nonPublicClass2File = JavaFileObjects.forSourceLines("foreign.NonPublicClass2",
+ "package foreign;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NonPublicClass2 {",
+ " @Inject NonPublicClass2(NoDepClass dep) {}",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import foreign.PublicClass;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " PublicClass publicClass();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import foreign.NoDepClass_Factory;",
+ "import foreign.NonPublicClass1_Factory;",
+ "import foreign.NonPublicClass2_Factory;",
+ "import foreign.PublicClass;",
+ "import foreign.PublicClass_Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " @SuppressWarnings(\"rawtypes\")",
+ " private Provider nonPublicClass1Provider;",
+ " @SuppressWarnings(\"rawtypes\")",
+ " private Provider nonPublicClass2Provider;",
+ " private Provider<PublicClass> publicClassProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.nonPublicClass1Provider =",
+ " NonPublicClass1_Factory.create(NoDepClass_Factory.create());",
+ " this.nonPublicClass2Provider =",
+ " NonPublicClass2_Factory.create(NoDepClass_Factory.create());",
+ " this.publicClassProvider = PublicClass_Factory.create(",
+ " nonPublicClass1Provider,",
+ " nonPublicClass2Provider,",
+ " NoDepClass_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public PublicClass publicClass() {",
+ " return publicClassProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ noDepClassFile,
+ publicClassFile,
+ nonPublicClass1File,
+ nonPublicClass2File,
+ componentFile))
+ .withCompilerOptions("-Xlint:rawtypes", "-Xlint:unchecked", "-Werror")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test public void memberInjectedType() {
+ JavaFileObject noDepClassFile = JavaFileObjects.forSourceLines("test.NoDepClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class NoDepClass {",
+ " @Inject NoDepClass() {}",
+ "}");
+ JavaFileObject aClassFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import foreign.B;",
+ "import javax.inject.Inject;",
+ "",
+ "final class A extends B {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject bClassFile = JavaFileObjects.forSourceLines("foreign.B",
+ "package foreign;",
+ "",
+ "import test.NoDepClass;",
+ "import javax.inject.Inject;",
+ "",
+ "public class B extends C {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject cClassFile = JavaFileObjects.forSourceLines("foreign.C",
+ "package foreign;",
+ "",
+ "import test.D;",
+ "import test.NoDepClass;",
+ "import javax.inject.Inject;",
+ "",
+ "class C extends D {",
+ " @Inject NoDepClass dep;",
+ "}");
+ JavaFileObject dClassFile = JavaFileObjects.forSourceLines("test.D",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public class D {",
+ " @Inject NoDepClass dep;",
+ "}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " void injectA(A a);",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private MembersInjector<A> aMembersInjector;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.aMembersInjector = A_MembersInjector.create(NoDepClass_Factory.create());",
+ " }",
+ "",
+ " @Override",
+ " public void injectA(A a) {",
+ " aMembersInjector.injectMembers(a);",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ noDepClassFile,
+ aClassFile,
+ bClassFile,
+ cClassFile,
+ dClassFile,
+ componentFile))
+ .withCompilerOptions("-Xlint:rawtypes", "-Xlint:unchecked", "-Werror")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
new file mode 100644
index 0000000..ca0494e
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
@@ -0,0 +1,1128 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.ABSTRACT_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.FINAL_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.GENERIC_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_CONSTRUCTOR_ON_INNER_CLASS;
+import static dagger.internal.codegen.ErrorMessages.INJECT_ON_PRIVATE_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_INJECT_CONSTRUCTORS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_QUALIFIERS;
+import static dagger.internal.codegen.ErrorMessages.MULTIPLE_SCOPES;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.PRIVATE_INJECT_METHOD;
+import static dagger.internal.codegen.ErrorMessages.QUALIFIER_ON_INJECT_CONSTRUCTOR;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_FIELD;
+import static dagger.internal.codegen.ErrorMessages.STATIC_INJECT_METHOD;
+
+@RunWith(JUnit4.class)
+// TODO(gak): add tests for generation in the default package.
+public final class InjectConstructorFactoryGeneratorTest {
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+ private static final JavaFileObject SCOPE_A =
+ JavaFileObjects.forSourceLines("test.ScopeA",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeA {}");
+ private static final JavaFileObject SCOPE_B =
+ JavaFileObjects.forSourceLines("test.ScopeB",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface ScopeB {}");
+
+ @Test public void injectOnPrivateConstructor() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateConstructor {",
+ " @Inject private PrivateConstructor() {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_ON_PRIVATE_CONSTRUCTOR).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnInnerClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class OuterClass {",
+ " class InnerClass {",
+ " @Inject InnerClass() {}",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_CONSTRUCTOR_ON_INNER_CLASS).in(file).onLine(7);
+ }
+
+ @Test public void injectConstructorOnAbstractClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "abstract class AbstractClass {",
+ " @Inject AbstractClass() {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(INJECT_CONSTRUCTOR_ON_ABSTRACT_CLASS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnGenericClass() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<T> {",
+ " @Inject GenericClass(T t) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
+ " private final Provider<T> tProvider;",
+ "",
+ " public GenericClass_Factory(Provider<T> tProvider) {",
+ " assert tProvider != null;",
+ " this.tProvider = tProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<T> get() {",
+ " return new GenericClass<T>(tProvider.get());",
+ " }",
+ "",
+ " public static <T> Factory<GenericClass<T>> create(Provider<T> tProvider) {",
+ " return new GenericClass_Factory<T>(tProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void fieldAndMethodGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject A a;",
+ "",
+ " @Inject GenericClass() {}",
+ "",
+ " @Inject void register(B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final MembersInjector<GenericClass<A, B>> membersInjector;",
+ "",
+ " public GenericClass_Factory(MembersInjector<GenericClass<A, B>> membersInjector) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " GenericClass<A, B> instance = new GenericClass<A, B>();",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " MembersInjector<GenericClass<A, B>> membersInjector) {",
+ " return new GenericClass_Factory<A, B>(membersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void genericClassWithNoDependencies() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<T> {",
+ " @Inject GenericClass() {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@SuppressWarnings(\"rawtypes\")",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum GenericClass_Factory implements Factory<GenericClass> {",
+ " INSTANCE;",
+ "",
+ " @Override",
+ " public GenericClass get() {",
+ " return new GenericClass();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " public static <T> Factory<GenericClass<T>> create() {",
+ " return (Factory) INSTANCE;",
+ " }",
+ "",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void twoGenericTypes() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject GenericClass(A a, B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aProvider, Provider<B> bProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " return new GenericClass<A, B>(aProvider.get(), bProvider.get());",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider) {",
+ " return new GenericClass_Factory<A, B>(aProvider, bProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void boundedGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.List;",
+ "",
+ "class GenericClass<A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>> {",
+ " @Inject GenericClass(A a, B b, C c) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>>",
+ " implements Factory<GenericClass<A, B, C>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ " private final Provider<C> cProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aProvider,",
+ " Provider<B> bProvider,",
+ " Provider<C> cProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " assert cProvider != null;",
+ " this.cProvider = cProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B, C> get() {",
+ " return new GenericClass<A, B, C>(aProvider.get(), bProvider.get(), cProvider.get());",
+ " }",
+ "",
+ " public static <A extends Number & Comparable<A>,",
+ " B extends List<? extends String>,",
+ " C extends List<? super String>> Factory<GenericClass<A, B, C>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider) {",
+ " return new GenericClass_Factory<A, B, C>(aProvider, bProvider, cProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "import dagger.Lazy;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject GenericClass(A a, A a2, Provider<A> pa, @QualifierA A qa, Lazy<A> la, ",
+ " String s, String s2, Provider<String> ps, ",
+ " @QualifierA String qs, Lazy<String> ls,",
+ " B b, B b2, Provider<B> pb, @QualifierA B qb, Lazy<B> lb) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines("test.GenericClass_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
+ " private final Provider<A> aAndA2AndPaAndLaProvider;",
+ " private final Provider<A> qaProvider;",
+ " private final Provider<String> sAndS2AndPsAndLsProvider;",
+ " private final Provider<String> qsProvider;",
+ " private final Provider<B> bAndB2AndPbAndLbProvider;",
+ " private final Provider<B> qbProvider;",
+ "",
+ " public GenericClass_Factory(Provider<A> aAndA2AndPaAndLaProvider,",
+ " Provider<A> qaProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
+ " Provider<String> qsProvider,",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
+ " assert aAndA2AndPaAndLaProvider != null;",
+ " this.aAndA2AndPaAndLaProvider = aAndA2AndPaAndLaProvider;",
+ " assert qaProvider != null;",
+ " this.qaProvider = qaProvider;",
+ " assert sAndS2AndPsAndLsProvider != null;",
+ " this.sAndS2AndPsAndLsProvider = sAndS2AndPsAndLsProvider;",
+ " assert qsProvider != null;",
+ " this.qsProvider = qsProvider;",
+ " assert bAndB2AndPbAndLbProvider != null;",
+ " this.bAndB2AndPbAndLbProvider = bAndB2AndPbAndLbProvider;",
+ " assert qbProvider != null;",
+ " this.qbProvider = qbProvider;",
+ " }",
+ "",
+ " @Override",
+ " public GenericClass<A, B> get() {",
+ " return new GenericClass<A, B>(",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider,",
+ " qaProvider.get(),",
+ " DoubleCheckLazy.create(aAndA2AndPaAndLaProvider),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider,",
+ " qsProvider.get(),",
+ " DoubleCheckLazy.create(sAndS2AndPsAndLsProvider),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider.get(),",
+ " DoubleCheckLazy.create(bAndB2AndPbAndLbProvider));",
+ " }",
+ "",
+ " public static <A, B> Factory<GenericClass<A, B>> create(",
+ " Provider<A> aAndA2AndPaAndLaProvider,",
+ " Provider<A> qaProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
+ " Provider<String> qsProvider,",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
+ " return new GenericClass_Factory<A, B>(",
+ " aAndA2AndPaAndLaProvider,",
+ " qaProvider,",
+ " sAndS2AndPsAndLsProvider,",
+ " qsProvider,",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void multipleInjectConstructors() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.TooManyInjectConstructors",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class TooManyInjectConstructors {",
+ " @Inject TooManyInjectConstructors() {}",
+ " TooManyInjectConstructors(int i) {}",
+ " @Inject TooManyInjectConstructors(String s) {}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MULTIPLE_INJECT_CONSTRUCTORS).in(file).onLine(6)
+ .and().withErrorContaining(MULTIPLE_INJECT_CONSTRUCTORS).in(file).onLine(8);
+ }
+
+ @Test public void multipleQualifiersOnInjectConstructorParameter() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierConstructorParam",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierConstructorParam {",
+ " @Inject MultipleQualifierConstructorParam(@QualifierA @QualifierB String s) {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ // for whatever reason, javac only reports the error once on the constructor
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructorOnClassWithMultipleScopes() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@ScopeA @ScopeB class MultipleScopeClass {",
+ " @Inject MultipleScopeClass() {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, SCOPE_A, SCOPE_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(MULTIPLE_SCOPES).in(file).onLine(5).atColumn(1)
+ .and().withErrorContaining(MULTIPLE_SCOPES).in(file).onLine(5).atColumn(9);
+ }
+
+ @Test public void injectConstructorWithQualifier() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleScopeClass {",
+ " @Inject",
+ " @QualifierA",
+ " @QualifierB",
+ " MultipleScopeClass() {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(QUALIFIER_ON_INJECT_CONSTRUCTOR).in(file).onLine(7)
+ .and().withErrorContaining(QUALIFIER_ON_INJECT_CONSTRUCTOR).in(file).onLine(8);
+ }
+
+ @Test public void finalInjectField() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.FinalInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class FinalInjectField {",
+ " @Inject final String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(FINAL_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectFieldError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectField {",
+ " @Inject private String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRIVATE_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectFieldWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectField {",
+ " @Inject private String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.privateMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void staticInjectFieldError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectField {",
+ " @Inject static String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(STATIC_INJECT_FIELD).in(file).onLine(6);
+ }
+
+ @Test public void staticInjectFieldWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectField {",
+ " @Inject static String s;",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.staticMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void multipleQualifiersOnField() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierInjectField",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierInjectField {",
+ " @Inject @QualifierA @QualifierB String s;",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor()).failsToCompile()
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6).atColumn(11)
+ .and().withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6).atColumn(23);
+ }
+
+ @Test public void abstractInjectMethod() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "abstract class AbstractInjectMethod {",
+ " @Inject abstract void method();",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(ABSTRACT_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectMethodError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectMethod {",
+ " @Inject private void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRIVATE_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void privateInjectMethodWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrivateInjectMethod {",
+ " @Inject private void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.privateMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void staticInjectMethodError() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectMethod {",
+ " @Inject static void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(STATIC_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void staticInjectMethodWarning() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class StaticInjectMethod {",
+ " @Inject static void method(){}",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .withCompilerOptions("-Adagger.staticMemberValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError(); // TODO: Verify warning message when supported
+ }
+
+ @Test public void genericInjectMethod() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericInjectMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AbstractInjectMethod {",
+ " @Inject <T> void method();",
+ "}");
+ assertAbout(javaSource()).that(file)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(GENERIC_INJECT_METHOD).in(file).onLine(6);
+ }
+
+ @Test public void multipleQualifiersOnInjectMethodParameter() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierMethodParam",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class MultipleQualifierMethodParam {",
+ " @Inject void method(@QualifierA @QualifierB String s) {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ // for whatever reason, javac only reports the error once on the method
+ .withErrorContaining(MULTIPLE_QUALIFIERS).in(file).onLine(6);
+ }
+
+ @Test public void injectConstructor() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(String s) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<String> sProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(sProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(Provider<String> sProvider) {",
+ " return new InjectConstructor_Factory(sProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test public void injectConstructorAndMembersInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AllInjections {",
+ " @Inject String s;",
+ " @Inject AllInjections(String s) {}",
+ " @Inject void s(String s) {}",
+ "}");
+ JavaFileObject expectedFactory = JavaFileObjects.forSourceLines(
+ "test.AllInjections_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class AllInjections_Factory ",
+ " implements Factory<AllInjections> {",
+ "",
+ " private final MembersInjector<AllInjections> membersInjector;",
+ " private final Provider<String> sProvider;",
+ "",
+ " public AllInjections_Factory(MembersInjector<AllInjections> membersInjector, ",
+ " Provider<String> sProvider) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override public AllInjections get() {",
+ " AllInjections instance = new AllInjections(sProvider.get());",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static Factory<AllInjections> create(",
+ " MembersInjector<AllInjections> membersInjector, ",
+ " Provider<String> sProvider) {",
+ " return new AllInjections_Factory(membersInjector, sProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedFactory);
+ }
+
+ @Test public void supertypeRequiresMemberInjection() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "class A {}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class B extends A {",
+ " @Inject B() {}",
+ "}");
+ JavaFileObject expectedFactory = JavaFileObjects.forSourceLines(
+ "test.B_Factory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class B_Factory implements Factory<B> {",
+ "",
+ " private final MembersInjector<B> membersInjector;",
+ "",
+ " public B_Factory(MembersInjector<B> membersInjector) {",
+ " assert membersInjector != null;",
+ " this.membersInjector = membersInjector;",
+ " }",
+ "",
+ " @Override public B get() {",
+ " B instance = new B();",
+ " membersInjector.injectMembers(instance);",
+ " return instance;",
+ " }",
+ "",
+ " public static Factory<B> create(MembersInjector<B> membersInjector) {",
+ " return new B_Factory(membersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(aFile, bFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expectedFactory);
+ }
+
+ @Test
+ public void wildcardDependency() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import java.util.List;",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(List<? extends Object> objects) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<List<? extends Object>> objectsProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<List<? extends Object>> objectsProvider) {",
+ " assert objectsProvider != null;",
+ " this.objectsProvider = objectsProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(objectsProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<List<? extends Object>> objectsProvider) {",
+ " return new InjectConstructor_Factory(objectsProvider);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void basicNameCollision() {
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Factory",
+ "package other.pkg;",
+ "",
+ "public class Factory {}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import other.pkg.Factory;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(Factory factory) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<other.pkg.Factory> factoryProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<other.pkg.Factory> factoryProvider) {",
+ " assert factoryProvider != null;",
+ " this.factoryProvider = factoryProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(factoryProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<other.pkg.Factory> factoryProvider) {",
+ " return new InjectConstructor_Factory(factoryProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void nestedNameCollision() {
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Outer",
+ "package other.pkg;",
+ "",
+ "public class Outer {",
+ " public class Factory {}",
+ "}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import other.pkg.Outer;",
+ "",
+ "class InjectConstructor {",
+ " @Inject InjectConstructor(Outer.Factory factory) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.pkg.Outer;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<Outer.Factory> factoryProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<Outer.Factory> factoryProvider) {",
+ " assert factoryProvider != null;",
+ " this.factoryProvider = factoryProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(factoryProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<Outer.Factory> factoryProvider) {",
+ " return new InjectConstructor_Factory(factoryProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void samePackageNameCollision() {
+ JavaFileObject samePackageInterface = JavaFileObjects.forSourceLines("test.CommonName",
+ "package test;",
+ "",
+ "public interface CommonName {}");
+ JavaFileObject differentPackageInterface = JavaFileObjects.forSourceLines(
+ "other.pkg.CommonName",
+ "package other.pkg;",
+ "",
+ "public interface CommonName {}");
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectConstructor implements CommonName {",
+ " @Inject InjectConstructor(other.pkg.CommonName otherPackage, CommonName samePackage) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.InjectConstructor_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import other.pkg.CommonName;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class InjectConstructor_Factory ",
+ " implements Factory<InjectConstructor> {",
+ "",
+ " private final Provider<CommonName> otherPackageProvider;",
+ " private final Provider<test.CommonName> samePackageProvider;",
+ "",
+ " public InjectConstructor_Factory(Provider<CommonName> otherPackageProvider,",
+ " Provider<test.CommonName> samePackageProvider) {",
+ " assert otherPackageProvider != null;",
+ " this.otherPackageProvider = otherPackageProvider;",
+ " assert samePackageProvider != null;",
+ " this.samePackageProvider = samePackageProvider;",
+ " }",
+ "",
+ " @Override public InjectConstructor get() {",
+ " return new InjectConstructor(otherPackageProvider.get(), samePackageProvider.get());",
+ " }",
+ "",
+ " public static Factory<InjectConstructor> create(",
+ " Provider<CommonName> otherPackageProvider,",
+ " Provider<test.CommonName> samePackageProvider) {",
+ " return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(samePackageInterface, differentPackageInterface, file))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expected);
+ }
+
+ @Test
+ public void noDeps() {
+ JavaFileObject simpleType = JavaFileObjects.forSourceLines("test.SimpleType",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class SimpleType {",
+ " @Inject SimpleType() {}",
+ "}");
+ JavaFileObject factory = JavaFileObjects.forSourceLines("test.SimpleType_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum SimpleType_Factory implements Factory<SimpleType> {",
+ " INSTANCE;",
+ "",
+ " @Override public SimpleType get() {",
+ " return new SimpleType();",
+ " }",
+ "",
+ " public static Factory<SimpleType> create() {",
+ " return INSTANCE;",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(simpleType)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factory);
+ }
+
+ @Test public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject aFactory = JavaFileObjects.forSourceLines(
+ "test.OuterType$A_Factory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "import test.OuterType.A;",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public enum OuterType$A_Factory implements Factory<A> {",
+ " INSTANCE;",
+ "",
+ " @Override public A get() {",
+ " return new A();",
+ " }",
+ "",
+ " public static Factory<A> create() {",
+ " return INSTANCE;",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(aFactory);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/KeyTest.java b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java
new file mode 100644
index 0000000..c1d622d
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.testing.compile.CompilationRule;
+import dagger.Module;
+import dagger.Provides;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Set;
+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;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.Provides.Type.SET;
+import static dagger.Provides.Type.SET_VALUES;
+
+/**
+ * Tests {@link Key}.
+ */
+@RunWith(JUnit4.class)
+public class KeyTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private Elements elements;
+ private Types types;
+ private Key.Factory keyFactory;
+
+ @Before public void setUp() {
+ this.types = compilationRule.getTypes();
+ this.elements = compilationRule.getElements();
+ this.keyFactory = new Key.Factory(types, elements);
+ }
+
+ @Test public void forInjectConstructorWithResolvedType() {
+ TypeElement typeElement =
+ compilationRule.getElements().getTypeElement(InjectedClass.class.getCanonicalName());
+ ExecutableElement constructor =
+ Iterables.getOnlyElement(ElementFilter.constructorsIn(typeElement.getEnclosedElements()));
+ assertThat(
+ keyFactory.forInjectConstructorWithResolvedType(constructor.getEnclosingElement().asType()))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(typeElement.asType())));
+ }
+
+ static final class InjectedClass {
+ @SuppressWarnings("unused")
+ @Inject InjectedClass(String s, int i) {}
+ }
+
+ @Test public void forProvidesMethod() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement moduleElement =
+ elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ assertThat(
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(stringType)));
+ }
+
+ @Module
+ static final class ProvidesMethodModule {
+ @Provides String provideString() {
+ return null;
+ }
+ }
+
+ @Test public void forProvidesMethod_qualified() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement qualifierElement =
+ elements.getTypeElement(TestQualifier.class.getCanonicalName());
+ TypeElement moduleElement =
+ elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ Key key =
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod);
+ assertThat(MoreTypes.equivalence().wrap(key.qualifier().get().getAnnotationType()))
+ .isEqualTo(MoreTypes.equivalence().wrap(qualifierElement.asType()));
+ assertThat(key.wrappedType()).isEqualTo(MoreTypes.equivalence().wrap(stringType));
+ }
+
+ @Test public void qualifiedKeyEquivalents() {
+ TypeElement moduleElement =
+ elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
+ ExecutableElement providesMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
+ Key provisionKey =
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod);
+
+ TypeMirror type = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement injectableElement =
+ elements.getTypeElement(QualifiedFieldHolder.class.getCanonicalName());
+ Element injectionField =
+ Iterables.getOnlyElement(ElementFilter.fieldsIn(injectableElement.getEnclosedElements()));
+ AnnotationMirror qualifier = Iterables.getOnlyElement(injectionField.getAnnotationMirrors());
+ Key injectionKey = keyFactory.forQualifiedType(Optional.<AnnotationMirror>of(qualifier), type);
+
+ assertThat(provisionKey).isEqualTo(injectionKey);
+ }
+
+ @Module
+ static final class QualifiedProvidesMethodModule {
+ @Provides
+ @TestQualifier(@InnerAnnotation)
+ String provideQualifiedString() {
+ return null;
+ }
+ }
+
+ static final class QualifiedFieldHolder {
+ @TestQualifier(@InnerAnnotation) String aString;
+ }
+
+ @Qualifier
+ @interface TestQualifier {
+ InnerAnnotation[] value();
+ }
+
+ @interface InnerAnnotation {}
+
+ @Test public void forProvidesMethod_sets() {
+ TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
+ TypeElement moduleElement =
+ elements.getTypeElement(SetProvidesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement providesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(
+ keyFactory.forProvidesMethod((ExecutableType) providesMethod.asType(), providesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(setOfStringsType)));
+ }
+ }
+
+ @Module
+ static final class SetProvidesMethodsModule {
+ @Provides(type = SET) String provideString() {
+ return null;
+ }
+
+ @Provides(type = SET_VALUES) Set<String> provideStrings() {
+ return null;
+ }
+ }
+
+ @Module
+ static final class PrimitiveTypes {
+ @Provides int foo() {
+ return 0;
+ }
+ }
+
+ @Module
+ static final class BoxedPrimitiveTypes {
+ @Provides Integer foo() {
+ return 0;
+ }
+ }
+
+ @Test public void primitiveKeysMatchBoxedKeys() {
+ TypeElement primitiveHolder = elements.getTypeElement(PrimitiveTypes.class.getCanonicalName());
+ ExecutableElement intMethod =
+ Iterables.getOnlyElement(ElementFilter.methodsIn(primitiveHolder.getEnclosedElements()));
+ TypeElement boxedPrimitiveHolder =
+ elements.getTypeElement(BoxedPrimitiveTypes.class.getCanonicalName());
+ ExecutableElement integerMethod = Iterables.getOnlyElement(
+ ElementFilter.methodsIn(boxedPrimitiveHolder.getEnclosedElements()));
+
+ // TODO(cgruber): Truth subject for TypeMirror and TypeElement
+ TypeMirror intType = intMethod.getReturnType();
+ assertThat(intType.getKind().isPrimitive()).isTrue();
+ TypeMirror integerType = integerMethod.getReturnType();
+ assertThat(integerType.getKind().isPrimitive()).isFalse();
+ assertThat(types.isSameType(intType, integerType)).named("type equality").isFalse();
+
+ Key intKey = keyFactory.forProvidesMethod((ExecutableType) intMethod.asType(), intMethod);
+ Key integerKey =
+ keyFactory.forProvidesMethod((ExecutableType) integerMethod.asType(), integerMethod);
+ assertThat(intKey).isEqualTo(integerKey);
+ }
+
+ @Test public void forProducesMethod() {
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeElement moduleElement =
+ elements.getTypeElement(ProducesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement producesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(keyFactory.forProducesMethod(
+ (ExecutableType) producesMethod.asType(), producesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(stringType)));
+ }
+ }
+
+ @ProducerModule
+ static final class ProducesMethodsModule {
+ @Produces String produceString() {
+ return null;
+ }
+
+ @Produces ListenableFuture<String> produceFutureString() {
+ return null;
+ }
+ }
+
+ @Test public void forProducesMethod_sets() {
+ TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
+ TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
+ TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
+ TypeElement moduleElement =
+ elements.getTypeElement(SetProducesMethodsModule.class.getCanonicalName());
+ for (ExecutableElement producesMethod
+ : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
+ assertThat(keyFactory.forProducesMethod(
+ (ExecutableType) producesMethod.asType(), producesMethod))
+ .isEqualTo(new AutoValue_Key(
+ Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
+ MoreTypes.equivalence().wrap(setOfStringsType)));
+ }
+ }
+
+ @ProducerModule
+ static final class SetProducesMethodsModule {
+ @Produces(type = Produces.Type.SET) String produceString() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET) ListenableFuture<String> produceFutureString() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET_VALUES) Set<String> produceStrings() {
+ return null;
+ }
+
+ @Produces(type = Produces.Type.SET_VALUES)
+ ListenableFuture<Set<String>> produceFutureStrings() {
+ return null;
+ }
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java
new file mode 100644
index 0000000..9e1b6dc
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java
@@ -0,0 +1,906 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.processor.AutoAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MapBindingComponentProcessorTest {
+
+ @Test
+ public void mapBindingsWithEnumKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+
+ JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathEnum, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution1)",
+ " .put(PathEnum.LOGIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathEnum, Provider<Handler>> dispatcher() {",
+ " return mapOfPathEnumAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithStringKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @StringKey(\"Admin\") Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @StringKey(\"Login\") Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<String, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfStringAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfStringAndProviderOfHandlerContribution2;",
+ " private Provider<Map<String, Provider<Handler>>>",
+ " mapOfStringAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfStringAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfStringAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfStringAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<String, Handler>builder(2)",
+ " .put(\"Admin\", mapOfStringAndProviderOfHandlerContribution1)",
+ " .put(\"Login\", mapOfStringAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<String, Provider<Handler>> dispatcher() {",
+ " return mapOfStringAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithWrappedKey() {
+ JavaFileObject mapModuleOneFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP)",
+ " @WrappedClassKey(Integer.class) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =
+ JavaFileObjects
+ .forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP)",
+ " @WrappedClassKey(Long.class) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject wrappedClassKeyFile = JavaFileObjects.forSourceLines("test.WrappedClassKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface WrappedClassKey {",
+ " Class<?> value();",
+ "}");
+ JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<WrappedClassKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfWrappedClassKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfWrappedClassKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<WrappedClassKey, Provider<Handler>>>",
+ " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<WrappedClassKey, Handler>builder(2)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
+ " mapOfWrappedClassKeyAndProviderOfHandlerContribution1)",
+ " .put(WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
+ " mapOfWrappedClassKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<WrappedClassKey, Provider<Handler>> dispatcher() {",
+ " return mapOfWrappedClassKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ wrappedClassKeyFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithNonProviderValue() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile = JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathEnum, Handler> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathEnumAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;",
+ " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathEnumAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
+ " .put(PathEnum.ADMIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution1)",
+ " .put(PathEnum.LOGIN,",
+ " mapOfPathEnumAndProviderOfHandlerContribution2)",
+ " .build();",
+ " this.mapOfPathEnumAndHandlerProvider =",
+ " MapFactory.create(mapOfPathEnumAndProviderOfHandlerProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathEnum, Handler> dispatcher() {",
+ " return mapOfPathEnumAndHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ HandlerFile,
+ LoginHandlerFile,
+ AdminHandlerFile,
+ componentFile)).
+ processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void injectMapWithoutMapBinding() {
+ JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.HashMap;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides Map<String, String> provideAMap() {",
+ " Map<String, String> map = new HashMap<String, String>();",
+ " map.put(\"Hello\", \"World\");",
+ " return map;",
+ " }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, String> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Map<String, String>> provideAMapProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.provideAMapProvider = MapModule_ProvideAMapFactory.create(builder.mapModule);",
+ " }",
+ "",
+ " @Override",
+ " public Map<String, String> dispatcher() {",
+ " return provideAMapProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModule mapModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModule == null) {",
+ " this.mapModule = new MapModule();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModule(MapModule mapModule) {",
+ " if (mapModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModule = mapModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(mapModuleFile,componentFile))
+ .processedWith(new ComponentProcessor()).compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapBindingsWithDuplicateKeys() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKey() {",
+ " return \"one\";",
+ " }",
+ "",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKeyAgain() {",
+ " return \"one again\";",
+ " }",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, Object> objects();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("The same map key is bound more than once")
+ .and()
+ .withErrorContaining("provideObjectForAKey()")
+ .and()
+ .withErrorContaining("provideObjectForAKeyAgain()")
+ .and()
+ .withErrorCount(1);
+ }
+
+ @Test
+ public void mapBindingsWithInconsistentKeyAnnotations() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.MapModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.mapkeys.StringKey;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "@Module",
+ "final class MapModule {",
+ " @Provides(type = MAP) @StringKey(\"AKey\") Object provideObjectForAKey() {",
+ " return \"one\";",
+ " }",
+ "",
+ " @Provides(type = MAP) @StringKeyTwo(\"BKey\") Object provideObjectForBKey() {",
+ " return \"two\";",
+ " }",
+ "}");
+ JavaFileObject stringKeyTwoFile =
+ JavaFileObjects.forSourceLines(
+ "test.StringKeyTwo",
+ "package test;",
+ "",
+ "import dagger.MapKey;",
+ "",
+ "@MapKey(unwrapValue = true)",
+ "public @interface StringKeyTwo {",
+ " String value();",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "",
+ "@Component(modules = {MapModule.class})",
+ "interface TestComponent {",
+ " Map<String, Object> objects();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module, stringKeyTwoFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("uses more than one @MapKey annotation type")
+ .and()
+ .withErrorContaining("provideObjectForAKey()")
+ .and()
+ .withErrorContaining("provideObjectForBKey()")
+ .and()
+ .withErrorCount(1);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java
new file mode 100644
index 0000000..191ee6c
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.processor.AutoAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MapKeyProcessorTest {
+ @Test
+ public void mapKeyCreatorFile() {
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"Defaultpath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject generatedKeyCreator =
+ JavaFileObjects.forSourceLines(
+ "test.PathKeyCreator",
+ "package test;",
+ "",
+ "import com.google.auto.value.AutoAnnotation;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class PathKeyCreator {",
+ " @AutoAnnotation",
+ " public static PathKey createPathKey(PathEnum value, String relativePath) {",
+ " return new AutoAnnotation_PathKeyCreator_createPathKey(value, relativePath);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(enumKeyFile, pathEnumFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedKeyCreator);
+ }
+
+ @Test
+ public void nestedMapKeyCreatorFile() {
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.Container",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "public interface Container {",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"Defaultpath\";",
+ "}",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject generatedKeyCreator =
+ JavaFileObjects.forSourceLines(
+ "test.Container$PathKeyCreator",
+ "package test;",
+ "",
+ "import com.google.auto.value.AutoAnnotation;",
+ "import javax.annotation.Generated;",
+ "import test.Container.PathKey",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class Container$PathKeyCreator {",
+ " @AutoAnnotation",
+ " public static PathKey createPathKey(PathEnum value, String relativePath) {",
+ " return new AutoAnnotation_Container$PathKeyCreator_createPathKey(",
+ " value, relativePath);",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(enumKeyFile, pathEnumFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedKeyCreator);
+ }
+
+ @Test
+ public void mapKeyComponentFileWithDisorderedKeyField() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(relativePath = \"AdminPath\", value = PathEnum.ADMIN)",
+ " Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.LOGIN, relativePath = \"LoginPath\")",
+ " Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"DefaultPath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject handlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject loginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"AdminPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution1)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathKey, Provider<Handler>> dispatcher() {",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void mapKeyComponentFileWithDefaultField() {
+ JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleOne {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.ADMIN) Handler provideAdminHandler() {",
+ " return new AdminHandler();",
+ " }",
+ "}");
+ JavaFileObject mapModuleTwoFile =JavaFileObjects.forSourceLines("test.MapModuleTwo",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.MAP;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class MapModuleTwo {",
+ " @Provides(type = MAP) @PathKey(value = PathEnum.LOGIN, relativePath = \"LoginPath\")",
+ " Handler provideLoginHandler() {",
+ " return new LoginHandler();",
+ " }",
+ "}");
+ JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
+ "package test;",
+ "import dagger.MapKey;",
+ "import java.lang.annotation.Retention;",
+ "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
+ "",
+ "@MapKey(unwrapValue = false)",
+ "@Retention(RUNTIME)",
+ "public @interface PathKey {",
+ " PathEnum value();",
+ " String relativePath() default \"DefaultPath\";",
+ "}");
+ JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
+ "package test;",
+ "",
+ "public enum PathEnum {",
+ " ADMIN,",
+ " LOGIN;",
+ "}");
+ JavaFileObject handlerFile = JavaFileObjects.forSourceLines("test.Handler",
+ "package test;",
+ "",
+ "interface Handler {}");
+ JavaFileObject loginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
+ "package test;",
+ "",
+ "class LoginHandler implements Handler {",
+ " public LoginHandler() {}",
+ "}");
+ JavaFileObject adminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
+ "package test;",
+ "",
+ "class AdminHandler implements Handler {",
+ " public AdminHandler() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
+ "interface TestComponent {",
+ " Map<PathKey, Provider<Handler>> dispatcher();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.internal.MapProviderFactory;",
+ "import java.util.Map;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution1;",
+ " private Provider<Handler> mapOfPathKeyAndProviderOfHandlerContribution2;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution1 =",
+ " MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
+ " this.mapOfPathKeyAndProviderOfHandlerContribution2 =",
+ " MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"DefaultPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution1)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " mapOfPathKeyAndProviderOfHandlerContribution2)",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Map<PathKey, Provider<Handler>> dispatcher() {",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private MapModuleOne mapModuleOne;",
+ " private MapModuleTwo mapModuleTwo;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " if (mapModuleOne == null) {",
+ " this.mapModuleOne = new MapModuleOne();",
+ " }",
+ " if (mapModuleTwo == null) {",
+ " this.mapModuleTwo = new MapModuleTwo();",
+ " }",
+ " return new DaggerTestComponent(this);",
+ " }",
+ "",
+ " public Builder mapModuleOne(MapModuleOne mapModuleOne) {",
+ " if (mapModuleOne == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleOne = mapModuleOne;",
+ " return this;",
+ " }",
+ "",
+ " public Builder mapModuleTwo(MapModuleTwo mapModuleTwo) {",
+ " if (mapModuleTwo == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.mapModuleTwo = mapModuleTwo;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ mapModuleOneFile,
+ mapModuleTwoFile,
+ enumKeyFile,
+ pathEnumFile,
+ handlerFile,
+ loginHandlerFile,
+ adminHandlerFile,
+ componentFile))
+ .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java
new file mode 100644
index 0000000..52be72a
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.compile.JavaFileObjects;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static javax.tools.StandardLocation.CLASS_OUTPUT;
+
+@RunWith(JUnit4.class)
+public class MembersInjectionTest {
+ @Test
+ public void parentClass_noInjectedMembers() {
+ JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class Child extends Parent {",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "public abstract class Parent {}");
+
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Child child();",
+ "}");
+ JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.MembersInjectors;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private Provider<Child> childProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.childProvider =",
+ " Child_Factory.create((MembersInjector) MembersInjectors.noOp());",
+ " }",
+ "",
+ " @Override",
+ " public Child child() {",
+ " return childProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {",
+ " }",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(childFile, parentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+
+ @Test
+ public void parentClass_injectedMembersInSupertype() {
+ JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public final class Child extends Parent {",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "public abstract class Parent {",
+ " @Inject Dep dep;",
+ "}");
+ JavaFileObject depFile = JavaFileObjects.forSourceLines("test.Dep",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep {",
+ " @Inject Dep() {}",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " Child child();",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestComponent implements TestComponent {",
+ " private MembersInjector<Child> childMembersInjector;",
+ " private Provider<Child> childProvider;",
+ "",
+ " private DaggerTestComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static TestComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.childMembersInjector = Child_MembersInjector.create(Dep_Factory.create());",
+ " this.childProvider = Child_Factory.create(childMembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public Child child() {",
+ " return childProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public TestComponent build() {",
+ " return new DaggerTestComponent(this);",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(childFile, parentFile, depFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(generatedComponent);
+ }
+
+ @Test public void fieldAndMethodGenerics() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GenericClass<A, B> {",
+ " @Inject A a;",
+ "",
+ " @Inject GenericClass() {}",
+ "",
+ " @Inject void register(B b) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.GenericClass_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "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) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(GenericClass<A, B> instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " instance.register(bProvider.get());",
+ " }",
+ "",
+ " public static <A, B> MembersInjector<GenericClass<A, B>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider) {",
+ " return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);",
+ " }",
+ "",
+ " public static <A, B> void injectA(GenericClass<A, B> instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static <A, B> void injectRegister(",
+ " GenericClass<A, B> instance, Provider<B> bProvider) {",
+ " instance.register(bProvider.get());",
+ " }",
+ "",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void subclassedGenericMembersInjectors() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject a2 = JavaFileObjects.forSourceLines("test.A2",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A2 {",
+ " @Inject A2() {}",
+ "}");
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Parent<X, Y> {",
+ " @Inject X x;",
+ " @Inject Y y;",
+ " @Inject A2 a2;",
+ "",
+ " @Inject Parent() {}",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Child<T> extends Parent<T, A> {",
+ " @Inject A a;",
+ " @Inject T t;",
+ "",
+ " @Inject Child() {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.Child_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "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) {",
+ " assert tAndXProvider != null;",
+ " this.tAndXProvider = tAndXProvider;",
+ " assert aAndYProvider != null;",
+ " this.aAndYProvider = aAndYProvider;",
+ " assert a2Provider != null;",
+ " this.a2Provider = a2Provider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(Child<T> instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " ((test.Parent) instance).x = tAndXProvider.get();",
+ " ((test.Parent) instance).y = aAndYProvider.get();",
+ " ((test.Parent) instance).a2 = a2Provider.get();",
+ " instance.a = aAndYProvider.get();",
+ " instance.t = tAndXProvider.get();",
+ " }",
+ "",
+ " public static <T> MembersInjector<Child<T>> create(",
+ " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
+ " return new Child_MembersInjector<T>(tAndXProvider, aAndYProvider, a2Provider);",
+ " }",
+ "",
+ " public static <T> void injectA(Child<T> instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static <T> void injectT(Child<T> instance, Provider<T> tProvider) {",
+ " instance.t = tProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(a, a2, parent, child))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void fieldInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.FieldInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class FieldInjection {",
+ " @Inject String string;",
+ " @Inject Lazy<String> lazyString;",
+ " @Inject Provider<String> stringProvider;",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.FieldInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class FieldInjection_MembersInjector",
+ " implements MembersInjector<FieldInjection> {",
+ " private final Provider<String> stringProvider;",
+ "",
+ " public FieldInjection_MembersInjector(Provider<String> stringProvider) {",
+ " assert stringProvider != null;",
+ " this.stringProvider = stringProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(FieldInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.string = stringProvider.get();",
+ " instance.lazyString = DoubleCheckLazy.create(stringProvider);",
+ " instance.stringProvider = stringProvider;",
+ " }",
+ "",
+ " public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {",
+ " return new FieldInjection_MembersInjector(stringProvider);",
+ " }",
+ "",
+ " public static void injectString(",
+ " FieldInjection instance, Provider<String> stringProvider) {",
+ " instance.string = stringProvider.get();",
+ " }",
+ "",
+ " public static void injectLazyString(",
+ " FieldInjection instance, Provider<String> lazyStringProvider) {",
+ " instance.lazyString = DoubleCheckLazy.create(lazyStringProvider);",
+ " }",
+ "",
+ " public static void injectStringProvider(",
+ " FieldInjection instance, Provider<String> stringProvider) {",
+ " instance.stringProvider = stringProvider;",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void methodInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.MethodInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class MethodInjection {",
+ " @Inject void noArgs() {}",
+ " @Inject void oneArg(String string) {}",
+ " @Inject void manyArgs(",
+ " String string, Lazy<String> lazyString, Provider<String> stringProvider) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.MethodInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.DoubleCheckLazy;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class MethodInjection_MembersInjector",
+ " implements MembersInjector<MethodInjection> {",
+ "",
+ " private final Provider<String> stringProvider;",
+ "",
+ " public MethodInjection_MembersInjector(Provider<String> stringProvider) {",
+ " assert stringProvider != null;",
+ " this.stringProvider = stringProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(MethodInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.noArgs();",
+ " instance.oneArg(stringProvider.get());",
+ " instance.manyArgs(stringProvider.get(), DoubleCheckLazy.create(stringProvider),",
+ " stringProvider);",
+ " }",
+ "",
+ " public static MembersInjector<MethodInjection> create(",
+ " Provider<String> stringProvider) {",
+ " return new MethodInjection_MembersInjector(stringProvider);",
+ " }",
+ "",
+ " public static void injectNoArgs(MethodInjection instance) {",
+ " instance.noArgs();",
+ " }",
+ "",
+ " public static void injectOneArg(",
+ " MethodInjection instance, Provider<String> stringProvider) {",
+ " instance.oneArg(stringProvider.get());",
+ " }",
+ "",
+ " public static void injectManyArgs(",
+ " MethodInjection instance,",
+ " Provider<String> stringProvider,",
+ " Provider<String> lazyStringProvider,",
+ " Provider<String> stringProvider2) {",
+ " instance.manyArgs(",
+ " stringProvider.get(),",
+ " DoubleCheckLazy.create(lazyStringProvider),",
+ " stringProvider2);",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test
+ public void mixedMemberInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines(
+ "test.MixedMemberInjection",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class MixedMemberInjection {",
+ " @Inject String string;",
+ " @Inject void setString(String s) {}",
+ " @Inject Object object;",
+ " @Inject void setObject(Object o) {}",
+ "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.MixedMemberInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "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) {",
+ " assert stringAndSProvider != null;",
+ " this.stringAndSProvider = stringAndSProvider;",
+ " assert objectAndOProvider != null;",
+ " this.objectAndOProvider = objectAndOProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(MixedMemberInjection instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.string = stringAndSProvider.get();",
+ " instance.object = objectAndOProvider.get();",
+ " instance.setString(stringAndSProvider.get());",
+ " instance.setObject(objectAndOProvider.get());",
+ " }",
+ "",
+ " public static MembersInjector<MixedMemberInjection> create(",
+ " Provider<String> stringAndSProvider,",
+ " Provider<Object> objectAndOProvider) {",
+ " return new MixedMemberInjection_MembersInjector(",
+ " stringAndSProvider, objectAndOProvider);",
+ " }",
+ " public static void injectString(",
+ " MixedMemberInjection instance, Provider<String> stringProvider) {",
+ " instance.string = stringProvider.get();",
+ " }",
+ "",
+ " public static void injectObject(",
+ " MixedMemberInjection instance, Provider<Object> objectProvider) {",
+ " instance.object = objectProvider.get();",
+ " }",
+ "",
+ " public static void injectSetString(",
+ " MixedMemberInjection instance, Provider<String> sProvider) {",
+ " instance.setString(sProvider.get());",
+ " }",
+ "",
+ " public static void injectSetObject(",
+ " MixedMemberInjection instance, Provider<Object> oProvider) {",
+ " instance.setObject(oProvider.get());",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expected);
+ }
+
+ @Test public void injectConstructorAndMembersInjection() {
+ JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class AllInjections {",
+ " @Inject String s;",
+ " @Inject AllInjections(String s) {}",
+ " @Inject void s(String s) {}",
+ "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class AllInjections_MembersInjector ",
+ " implements MembersInjector<AllInjections> {",
+ "",
+ " private final Provider<String> sProvider;",
+ "",
+ " public AllInjections_MembersInjector(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(AllInjections instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.s = sProvider.get();",
+ " instance.s(sProvider.get());",
+ " }",
+ "",
+ " public static MembersInjector<AllInjections> create(Provider<String> sProvider) {",
+ " return new AllInjections_MembersInjector(sProvider);",
+ " }",
+ "",
+ " public static void injectS(AllInjections instance, Provider<String> sProvider) {",
+ " instance.s = sProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(file)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedMembersInjector);
+ }
+
+ @Test public void supertypeMembersInjection() {
+ JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "class A {}");
+ JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class B extends A {",
+ " @Inject String s;",
+ "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<String> sProvider;",
+ "",
+ " public B_MembersInjector(Provider<String> sProvider) {",
+ " assert sProvider != null;",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.s = sProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<String> sProvider) {",
+ " return new B_MembersInjector(sProvider);",
+ " }",
+ " public static void injectS(B instance, Provider<String> sProvider) {",
+ " instance.s = sProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(aFile, bFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(expectedMembersInjector);
+ }
+
+ @Test
+ public void simpleComponentWithNesting() {
+ JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines(
+ "test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject bMembersInjector = JavaFileObjects.forSourceLines(
+ "test.OuterType$B_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<A> aProvider;",
+ "",
+ " public OuterType$B_MembersInjector(Provider<A> aProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<A> aProvider) {",
+ " return new OuterType$B_MembersInjector(aProvider);",
+ " }",
+ "",
+ " public static void injectA(B instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(nestedTypesFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(bMembersInjector);
+ }
+
+ @Test
+ public void componentWithNestingAndGeneratedType() {
+ JavaFileObject nestedTypesFile =
+ JavaFileObjects.forSourceLines(
+ "test.OuterType",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Inject;",
+ "",
+ "final class OuterType {",
+ " @Inject GeneratedType generated;",
+ " static class A {",
+ " @Inject A() {}",
+ " }",
+ " static class B {",
+ " @Inject A a;",
+ " }",
+ " @Component interface SimpleComponent {",
+ " A a();",
+ " void inject(B b);",
+ " }",
+ "}");
+ JavaFileObject bMembersInjector =
+ JavaFileObjects.forSourceLines(
+ "test.OuterType$B_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.OuterType.A;",
+ "import test.OuterType.B;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<A> aProvider;",
+ "",
+ " public OuterType$B_MembersInjector(Provider<A> aProvider) {",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " if (instance == null) {",
+ " throw new NullPointerException(\"Cannot inject members into a null reference\");",
+ " }",
+ " instance.a = aProvider.get();",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<A> aProvider) {",
+ " return new OuterType$B_MembersInjector(aProvider);",
+ " }",
+ "",
+ " public static void injectA(B instance, Provider<A> aProvider) {",
+ " instance.a = aProvider.get();",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(nestedTypesFile)
+ .processedWith(
+ new ComponentProcessor(),
+ new AbstractProcessor() {
+ private boolean done;
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(
+ Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!done) {
+ done = true;
+ try (Writer writer =
+ processingEnv
+ .getFiler()
+ .createSourceFile("test.GeneratedType")
+ .openWriter()) {
+ writer.write(
+ Joiner.on('\n')
+ .join(
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class GeneratedType {",
+ " @Inject GeneratedType() {}",
+ "}"));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return false;
+ }
+ })
+ .compilesWithoutError()
+ .and()
+ .generatesSources(bMembersInjector);
+ }
+
+ @Test
+ public void lowerCaseNamedMembersInjector_forLowerCaseType() {
+ JavaFileObject foo =
+ JavaFileObjects.forSourceLines(
+ "test.foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class foo {",
+ " @Inject String string;",
+ "}");
+ JavaFileObject fooModule =
+ JavaFileObjects.forSourceLines(
+ "test.fooModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class fooModule {",
+ " @Provides String string() { return \"foo\"; }",
+ "}");
+ JavaFileObject fooComponent =
+ JavaFileObjects.forSourceLines(
+ "test.fooComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = fooModule.class)",
+ "interface fooComponent {",
+ " void inject(foo target);",
+ "}");
+
+ assertAbout(javaSources())
+ .that(ImmutableList.of(foo, fooModule, fooComponent))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesFileNamed(CLASS_OUTPUT, "test", "foo_MembersInjector.class");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java b/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java
new file mode 100644
index 0000000..45791c7
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MethodSignatureFormatterTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.common.collect.Iterables;
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.InnerClass;
+import javax.inject.Singleton;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+@RunWith(JUnit4.class)
+public class MethodSignatureFormatterTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ static class OuterClass {
+ @interface Foo {
+ Class<?> bar();
+ }
+
+ static class InnerClass {
+ @Foo(bar = String.class)
+ @Singleton
+ String foo(@SuppressWarnings("unused") int a, ImmutableList<Boolean> blah) { return "foo"; }
+ }
+ }
+
+ @Test public void methodSignatureTest() {
+ Elements elements = compilationRule.getElements();
+ TypeElement inner = elements.getTypeElement(InnerClass.class.getCanonicalName());
+ ExecutableElement method = Iterables.getOnlyElement(methodsIn(inner.getEnclosedElements()));
+ String formatted = new MethodSignatureFormatter(compilationRule.getTypes()).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.
+ assertThat(formatted).contains("@Singleton");
+ assertThat(formatted).doesNotContain("@javax.inject.Singleton"); // maybe more importantly
+ assertThat(formatted)
+ .contains("@dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.Foo"
+ + "(bar=String.class)");
+ assertThat(formatted).contains(" String "); // return type compressed
+ assertThat(formatted).contains("int, ImmutableList<Boolean>)"); // parameters compressed.
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java b/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java
new file mode 100644
index 0000000..03ec35d
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MissingBindingSuggestionsTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MissingBindingSuggestionsTest {
+ private static JavaFileObject injectable(String className, String constructorParams) {
+ return JavaFileObjects.forSourceLines("test." + className,
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class " + className +" {",
+ " @Inject " + className + "(" + constructorParams + ") {}",
+ "}");
+ }
+
+ private static JavaFileObject emptyInterface(String interfaceName) {
+ return JavaFileObjects.forSourceLines("test." + interfaceName,
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "interface " + interfaceName +" {}");
+ }
+
+ @Test public void suggestsBindingInSeparateComponent() {
+ JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface FooComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject barModule = JavaFileObjects.forSourceLines("test.BarModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class BarModule {",
+ " @Provides Bar provideBar() {return null;}",
+ "}");
+ JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {BarModule.class})",
+ "interface BarComponent {",
+ " Bar getBar();",
+ "}");
+ JavaFileObject foo = injectable("Foo", "Bar bar");
+ JavaFileObject bar = emptyInterface("Bar");
+
+ JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TopComponent {",
+ " FooComponent getFoo();",
+ " BarComponent getBar(BarModule barModule);",
+ "}");
+
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ fooComponent, barComponent, topComponent, foo, bar, barModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("A binding with matching key exists in component: test.BarComponent");
+ }
+
+ @Test public void suggestsBindingInNestedSubcomponent() {
+ JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface FooComponent {",
+ " Foo getFoo();",
+ "}");
+ JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent()",
+ "interface BarComponent {",
+ " BazComponent getBaz();",
+ "}");
+ JavaFileObject bazModule = JavaFileObjects.forSourceLines("test.BazModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class BazModule {",
+ " @Provides Baz provideBaz() {return null;}",
+ "}");
+ JavaFileObject bazComponent = JavaFileObjects.forSourceLines("test.BazComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {BazModule.class})",
+ "interface BazComponent {",
+ " Baz getBaz();",
+ "}");
+ JavaFileObject foo = injectable("Foo", "Baz baz");
+ JavaFileObject baz = emptyInterface("Baz");
+
+ JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TopComponent {",
+ " FooComponent getFoo();",
+ " BarComponent getBar();",
+ "}");
+
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ fooComponent, barComponent, bazComponent, topComponent, foo, baz, bazModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("A binding with matching key exists in component: test.BazComponent");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
new file mode 100644
index 0000000..72248e0
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.writer.StringLiteral;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+
+@RunWith(JUnit4.class)
+public class ModuleFactoryGeneratorTest {
+
+ private final JavaFileObject NULLABLE = JavaFileObjects.forSourceLines("test.Nullable",
+ "package test;",
+ "public @interface Nullable {}");
+
+ private static final StringLiteral NPE_LITERAL =
+ StringLiteral.forValue(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD);
+
+ // TODO(gak): add tests for invalid combinations of scope and qualifier annotations like we have
+ // for @Inject
+
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, "Provides");
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, "Provides", "Module");
+ }
+
+ @Test public void providesMethodNotInModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE));
+ }
+
+ @Test public void providesMethodAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @Provides abstract String provideString();",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_ABSTRACT));
+ }
+
+ @Test public void providesMethodPrivate() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides private String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_PRIVATE));
+ }
+
+ @Test public void providesMethodReturnVoid() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides void provideNothing() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE));
+ }
+
+ @Test public void providesMethodWithTypeParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides <T> String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER));
+ }
+
+ @Test public void providesMethodSetValuesWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set<?> provideWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void providesMethodSetValuesRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set provideSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void providesMethodSetValuesNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) List<String> provideStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void modulesWithTypeParamsMustBeAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule<A> {}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MODULES_WITH_TYPE_PARAMS_MUST_BE_ABSTRACT);
+ }
+
+ @Test public void provideOverriddenByNoProvide() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Parent {",
+ " @Provides String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.METHOD_OVERRIDES_PROVIDES_METHOD,
+ "Provides", "@Provides String test.Parent.foo()"));
+ }
+
+ @Test public void provideOverriddenByProvide() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Parent {",
+ " @Provides String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " @Provides String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ "Provides", "@Provides String test.Parent.foo()"));
+ }
+
+ @Test public void providesOverridesNonProvides() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "class Parent {",
+ " String foo() { return null; }",
+ "}");
+ JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class Child extends Parent{",
+ " @Provides String foo() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, child))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.PROVIDES_METHOD_OVERRIDES_ANOTHER,
+ "Provides", "String test.Parent.foo()"));
+ }
+
+ @Test public void validatesIncludedModules() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = Void.class)",
+ "class TestModule {}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(module))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(
+ ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED, "java.lang.Void", "@Module"));
+ }
+
+ @Test public void referencedModulesMustNotBeAbstract() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = AbstractModule.class)",
+ "class TestModule {}");
+ JavaFileObject abstractModule = JavaFileObjects.forSourceLines("test.AbstractModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class AbstractModule {}");
+ assertAbout(javaSources()).that(ImmutableList.of(module, abstractModule))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(ErrorMessages.REFERENCED_MODULES_MUST_NOT_BE_ABSTRACT,
+ "test.AbstractModule"));
+ }
+
+ @Test public void singleProvidesMethodNoArgs() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public String get() {",
+ " String provided = module.provideString();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void singleProvidesMethodNoArgs_disableNullable() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public String get() {",
+ " return module.provideString();",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .withCompilerOptions("-Adagger.nullableValidation=WARNING")
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void nullableProvides() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides @Nullable String provideString() { return null; }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<String> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " @Nullable",
+ " public String get() {",
+ " return module.provideString();",
+ " }",
+ "",
+ " public static Factory<String> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, NULLABLE))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+
+ @Test public void multipleProvidesMethods() {
+ JavaFileObject classXFile = JavaFileObjects.forSourceLines("test.X",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class X {",
+ " @Inject public String s;",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import java.util.Arrays;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides List<Object> provideObjects(",
+ " @QualifierA Object a, @QualifierB Object b, MembersInjector<X> x) {",
+ " return Arrays.asList(a, b);",
+ " }",
+ "",
+ " @Provides @QualifierA Object provideAObject() {",
+ " return new Object();",
+ " }",
+ "",
+ " @Provides @QualifierB Object provideBObject() {",
+ " return new Object();",
+ " }",
+ "}");
+ JavaFileObject listFactoryFile = JavaFileObjects.forSourceLines(
+ "TestModule_ProvideObjectsFactory",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideObjectsFactory implements Factory<List<Object>> {",
+ " private final TestModule module;",
+ " private final Provider<Object> aProvider;",
+ " private final Provider<Object> bProvider;",
+ " private final MembersInjector<X> xMembersInjector;",
+ "",
+ " public TestModule_ProvideObjectsFactory(",
+ " TestModule module,",
+ " Provider<Object> aProvider,",
+ " Provider<Object> bProvider,",
+ " MembersInjector<X> xMembersInjector) {",
+ " assert module != null;",
+ " this.module = module;",
+ " assert aProvider != null;",
+ " this.aProvider = aProvider;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " assert xMembersInjector != null;",
+ " this.xMembersInjector = xMembersInjector;",
+ " }",
+ "",
+ " @Override public List<Object> get() {",
+ " List<Object> provided =",
+ " module.provideObjects(aProvider.get(), bProvider.get(), xMembersInjector);",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<List<Object>> create(",
+ " TestModule module,",
+ " Provider<Object> aProvider,",
+ " Provider<Object> bProvider,",
+ " MembersInjector<X> xMembersInjector) {",
+ " return new TestModule_ProvideObjectsFactory(",
+ " module, aProvider, bProvider, xMembersInjector);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(
+ ImmutableList.of(classXFile, moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(listFactoryFile);
+ }
+
+ @Test public void providesSetElement() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import java.util.logging.Logger;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET) String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Collections;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringFactory implements Factory<Set<String>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<String> get() {",
+ " return Collections.<String>singleton(module.provideString());",
+ " }",
+ "",
+ " public static Factory<Set<String>> create(TestModule module) {",
+ " return new TestModule_ProvideStringFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void providesSetElementWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "import java.util.logging.Logger;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.ArrayList;",
+ "import java.util.List;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET) List<List<?>> provideWildcardList() {",
+ " return new ArrayList<>();",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines(
+ "TestModule_ProvideWildcardListFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Collections;",
+ "import java.util.List;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideWildcardListFactory implements "
+ + "Factory<Set<List<List<?>>>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideWildcardListFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<List<List<?>>> get() {",
+ " return Collections.<List<List<?>>>singleton(module.provideWildcardList());",
+ " }",
+ "",
+ " public static Factory<Set<List<List<?>>>> create(TestModule module) {",
+ " return new TestModule_ProvideWildcardListFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void providesSetValues() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.Provides.Type.SET_VALUES;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides(type = SET_VALUES) Set<String> provideStrings() {",
+ " return null;",
+ " }",
+ "}");
+ JavaFileObject factoryFile = JavaFileObjects.forSourceLines("TestModule_ProvideStringsFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.Set;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {",
+ " private final TestModule module;",
+ "",
+ " public TestModule_ProvideStringsFactory(TestModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override public Set<String> get() {",
+ " Set<String> provided = module.provideStrings();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Set<String>> create(TestModule module) {",
+ " return new TestModule_ProvideStringsFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(factoryFile);
+ }
+
+ @Test public void multipleProvidesMethodsWithSameName() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides Object provide(int i) {",
+ " return i;",
+ " }",
+ "",
+ " @Provides String provide() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_WITH_SAME_NAME)).in(moduleFile).onLine(8)
+ .and().withErrorContaining(formatErrorMessage(BINDING_METHOD_WITH_SAME_NAME))
+ .in(moduleFile).onLine(12);
+ }
+
+ @Test
+ public void providedTypes() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.io.Closeable;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String string() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides Set<String> strings() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides Set<? extends Closeable> closeables() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides String[] stringArray() {",
+ " return null;",
+ " }",
+ "",
+ " @Provides int integer() {",
+ " return 0;",
+ " }",
+ "",
+ " @Provides int[] integers() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test
+ public void privateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "final class Enclosing {",
+ " @Module private static final class PrivateModule {",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be private.")
+ .in(moduleFile).onLine(6);
+ }
+
+ @Test
+ public void enclosedInPrivateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "final class Enclosing {",
+ " private static final class PrivateEnclosing {",
+ " @Module static final class TestModule {",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be enclosed in private types.")
+ .in(moduleFile).onLine(7);
+ }
+
+ @Test
+ public void publicModuleNonPublicIncludes() {
+ JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(includes = {",
+ " NonPublicModule1.class, OtherPublicModule.class, NonPublicModule2.class",
+ "})",
+ "public final class PublicModule {",
+ "}");
+ JavaFileObject nonPublicModule1File = JavaFileObjects.forSourceLines("test.NonPublicModule1",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class NonPublicModule1 {",
+ "}");
+ JavaFileObject nonPublicModule2File = JavaFileObjects.forSourceLines("test.NonPublicModule2",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class NonPublicModule2 {",
+ "}");
+ JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "public final class OtherPublicModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ publicModuleFile, nonPublicModule1File, nonPublicModule2File, otherPublicModuleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make "
+ + "test.NonPublicModule1 and test.NonPublicModule2 public.")
+ .in(publicModuleFile).onLine(8);
+ }
+
+ @Test
+ public void genericSubclassedModule() {
+ JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.List;",
+ "import java.util.ArrayList;",
+ "",
+ "@Module",
+ "abstract class ParentModule<A extends CharSequence,",
+ " B,",
+ " C extends Number & Comparable<C>> {",
+ " @Provides List<B> provideListB(B b) {",
+ " List<B> list = new ArrayList<B>();",
+ " list.add(b);",
+ " return list;",
+ " }",
+ "}");
+ JavaFileObject numberChild = JavaFileObjects.forSourceLines("test.ChildNumberModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildNumberModule extends ParentModule<String, Number, Double> {",
+ " @Provides Number provideNumber() { return 1; }",
+ "}");
+ JavaFileObject integerChild = JavaFileObjects.forSourceLines("test.ChildIntegerModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ChildIntegerModule extends ParentModule<StringBuilder, Integer, Float> {",
+ " @Provides Integer provideInteger() { return 2; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.C",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.List;",
+ "",
+ "@Component(modules={ChildNumberModule.class, ChildIntegerModule.class})",
+ "interface C {",
+ " List<Number> numberList();",
+ " List<Integer> integerList();",
+ "}");
+ JavaFileObject listBFactory = JavaFileObjects.forSourceLines(
+ "test.ParentModule_ProvidesListBFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import java.util.List;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "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;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public ParentModule_ProvideListBFactory(",
+ " ParentModule<A, B, C> module, Provider<B> bProvider) {",
+ " assert module != null;",
+ " this.module = module;",
+ " assert bProvider != null;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " @Override",
+ " public List<B> get() { ",
+ " List<B> provided = module.provideListB(bProvider.get());",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
+ " Factory<List<B>> create(ParentModule<A, B, C> module, Provider<B> bProvider) {",
+ " return new ParentModule_ProvideListBFactory<A, B, C>(module, bProvider);",
+ " }",
+ "}");
+ JavaFileObject numberFactory = JavaFileObjects.forSourceLines(
+ "test.ChildNumberModule_ProvideNumberFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class ChildNumberModule_ProvideNumberFactory implements Factory<Number> {",
+ " private final ChildNumberModule module;",
+ "",
+ " public ChildNumberModule_ProvideNumberFactory(ChildNumberModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " public Number get() { ",
+ " Number provided = module.provideNumber();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Number> create(ChildNumberModule module) {",
+ " return new ChildNumberModule_ProvideNumberFactory(module);",
+ " }",
+ "}");
+ JavaFileObject integerFactory = JavaFileObjects.forSourceLines(
+ "test.ChildIntegerModule_ProvideIntegerFactory",
+ "package test;",
+ "",
+ "import dagger.internal.Factory;",
+ "import javax.annotation.Generated;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class ChildIntegerModule_ProvideIntegerFactory",
+ " implements Factory<Integer> {",
+ " private final ChildIntegerModule module;",
+ "",
+ " public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {",
+ " assert module != null;",
+ " this.module = module;",
+ " }",
+ "",
+ " @Override",
+ " public Integer get() { ",
+ " Integer provided = module.provideInteger();",
+ " if (provided == null) {",
+ " throw new NullPointerException(" + NPE_LITERAL + ");",
+ " }",
+ " return provided;",
+ " }",
+ "",
+ " public static Factory<Integer> create(ChildIntegerModule module) {",
+ " return new ChildIntegerModule_ProvideIntegerFactory(module);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(parent, numberChild, integerChild, component))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(listBFactory, numberFactory, integerFactory);
+ }
+
+ @Test public void providesMethodMultipleQualifiers() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "import javax.annotation.Nullable;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides @QualifierA @QualifierB String provideString() {",
+ " return \"foo\";",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java b/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java
new file mode 100644
index 0000000..27e720d
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/MultipleRequestTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class MultipleRequestTest {
+ private static final JavaFileObject DEP_FILE = JavaFileObjects.forSourceLines("test.Dep",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Dep {",
+ " @Inject Dep() {}",
+ "}");
+
+ @Test public void multipleRequests_constructor() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.ConstructorInjectsMultiple",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ConstructorInjectsMultiple {",
+ " @Inject ConstructorInjectsMultiple(Dep d1, Dep d2) {}",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " ConstructorInjectsMultiple get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void multipleRequests_field() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.FieldInjectsMultiple",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class FieldInjectsMultiple {",
+ " @Inject Dep d1;",
+ " @Inject Dep d2;",
+ " @Inject FieldInjectsMultiple() {}",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface SimpleComponent {",
+ " FieldInjectsMultiple get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+
+ @Test public void multipleRequests_providesMethod() {
+ assert_().about(javaSources())
+ .that(ImmutableList.of(
+ DEP_FILE,
+ JavaFileObjects.forSourceLines("test.FieldInjectsMultiple",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class SimpleModule {",
+ " @Provides Object provide(Dep d1, Dep d2) {",
+ " return null;",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines("test.SimpleComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = SimpleModule.class)",
+ "interface SimpleComponent {",
+ " Object get();",
+ "}")))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java b/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
new file mode 100644
index 0000000..f9c2878
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// TODO(beder): Merge the error-handling tests with the ModuleFactoryGeneratorTest.
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_ABSTRACT;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_MUST_RETURN_A_VALUE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_NOT_IN_MODULE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_PRIVATE;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_SET_VALUES_RAW_SET;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_TYPE_PARAMETER;
+import static dagger.internal.codegen.ErrorMessages.BINDING_METHOD_WITH_SAME_NAME;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RAW_FUTURE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_RETURN_TYPE;
+import static dagger.internal.codegen.ErrorMessages.PRODUCES_METHOD_SET_VALUES_RETURN_SET;
+import static dagger.internal.codegen.ErrorMessages.PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS;
+
+@RunWith(JUnit4.class)
+public class ProducerModuleFactoryGeneratorTest {
+ private String formatErrorMessage(String msg) {
+ return String.format(msg, "Produces");
+ }
+
+ private String formatModuleErrorMessage(String msg) {
+ return String.format(msg, "Produces", "ProducerModule");
+ }
+
+ @Test public void producesMethodNotInModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.Produces;",
+ "",
+ "final class TestModule {",
+ " @Produces String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatModuleErrorMessage(BINDING_METHOD_NOT_IN_MODULE));
+ }
+
+ @Test public void producesMethodAbstract() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "abstract class TestModule {",
+ " @Produces abstract String produceString();",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_ABSTRACT));
+ }
+
+ @Test public void producesMethodPrivate() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces private String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_PRIVATE));
+ }
+
+ @Test public void producesMethodReturnVoid() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces void produceNothing() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_MUST_RETURN_A_VALUE));
+ }
+
+ @Test public void producesMethodReturnRawFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture produceRaw() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RAW_FUTURE);
+ }
+
+ @Test public void producesMethodReturnWildcardFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture<?> produceRaw() {}",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodWithTypeParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces <T> String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_TYPE_PARAMETER));
+ }
+
+ @Test public void producesMethodSetValuesWildcard() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) Set<?> produceWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodSetValuesRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) Set produceSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void producesMethodSetValuesNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.List;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) List<String> produceStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void producesMethodSetValuesWildcardInFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<Set<?>> produceWildcard() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_RETURN_TYPE);
+ }
+
+ @Test public void producesMethodSetValuesFutureRawSet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<Set> produceSomething() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(formatErrorMessage(BINDING_METHOD_SET_VALUES_RAW_SET));
+ }
+
+ @Test public void producesMethodSetValuesFutureNotASet() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import static dagger.producers.Produces.Type.SET_VALUES;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "import java.util.List;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces(type = SET_VALUES) ListenableFuture<List<String>> produceStrings() {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PRODUCES_METHOD_SET_VALUES_RETURN_SET);
+ }
+
+ @Test public void multipleProducesMethodsWithSameName() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces Object produce(int i) {",
+ " return i;",
+ " }",
+ "",
+ " @Produces String produce() {",
+ " return \"\";",
+ " }",
+ "}");
+ String errorMessage = String.format(BINDING_METHOD_WITH_SAME_NAME, "Produces");
+ assertAbout(javaSource()).that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(errorMessage).in(moduleFile).onLine(8)
+ .and().withErrorContaining(errorMessage).in(moduleFile).onLine(12);
+ }
+
+ @Test
+ public void privateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "final class Enclosing {",
+ " @ProducerModule private static final class PrivateModule {",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be private.")
+ .in(moduleFile).onLine(6);
+ }
+
+ @Test
+ public void enclosedInPrivateModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "final class Enclosing {",
+ " private static final class PrivateEnclosing {",
+ " @ProducerModule static final class TestModule {",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("Modules cannot be enclosed in private types.")
+ .in(moduleFile).onLine(7);
+ }
+
+ @Test
+ public void includesNonModule() {
+ JavaFileObject xFile =
+ JavaFileObjects.forSourceLines("test.X", "package test;", "", "public final class X {}");
+ JavaFileObject moduleFile =
+ JavaFileObjects.forSourceLines(
+ "test.FooModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule(includes = X.class)",
+ "public final class FooModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(xFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(
+ ErrorMessages.REFERENCED_MODULE_NOT_ANNOTATED,
+ "X",
+ "one of @Module, @ProducerModule"));
+ }
+
+ @Test
+ public void publicModuleNonPublicIncludes() {
+ JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule(includes = {",
+ " NonPublicModule1.class, OtherPublicModule.class, NonPublicModule2.class",
+ "})",
+ "public final class PublicModule {",
+ "}");
+ JavaFileObject nonPublicModule1File = JavaFileObjects.forSourceLines("test.NonPublicModule1",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "final class NonPublicModule1 {",
+ "}");
+ JavaFileObject nonPublicModule2File = JavaFileObjects.forSourceLines("test.NonPublicModule2",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "final class NonPublicModule2 {",
+ "}");
+ JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "",
+ "@ProducerModule",
+ "public final class OtherPublicModule {",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(
+ publicModuleFile, nonPublicModule1File, nonPublicModule2File, otherPublicModuleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is public, but it includes non-public "
+ + "(or effectively non-public) modules. "
+ + "Either reduce the visibility of this module or make "
+ + "test.NonPublicModule1 and test.NonPublicModule2 public.")
+ .in(publicModuleFile).onLine(8);
+ }
+
+ @Test public void singleProducesMethodNoArgsFuture() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces ListenableFuture<String> produceString() {",
+ " return null;",
+ " }",
+ "}");
+ JavaFileObject factoryFile =
+ JavaFileObjects.forSourceLines(
+ "TestModule_ProduceStringFactory",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.AsyncFunction;",
+ "import com.google.common.util.concurrent.Futures;",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.internal.AbstractProducer;",
+ "import dagger.producers.monitoring.ProducerMonitor;",
+ "import dagger.producers.monitoring.ProducerToken;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.concurrent.Executor;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class TestModule_ProduceStringFactory extends AbstractProducer<String> {",
+ " private final TestModule module;",
+ " private final Executor executor;",
+ " private final Provider<ProductionComponentMonitor> monitorProvider;",
+ "",
+ " public TestModule_ProduceStringFactory(",
+ " TestModule module,",
+ " Executor executor,",
+ " Provider<ProductionComponentMonitor> monitorProvider) {",
+ " super(",
+ " monitorProvider,",
+ " ProducerToken.create(TestModule_ProduceStringFactory.class));",
+ " assert module != null;",
+ " this.module = module;",
+ " assert executor != null;",
+ " this.executor = executor;",
+ " assert monitorProvider != null;",
+ " this.monitorProvider = monitorProvider;",
+ " }",
+ "",
+ " @Override protected ListenableFuture<String> compute(",
+ " final ProducerMonitor monitor) {",
+ " return Futures.transform(",
+ " Futures.<Void>immediateFuture(null),",
+ " new AsyncFunction<Void, String>() {",
+ " @Override public ListenableFuture<String> apply(Void ignoredVoidArg) {",
+ " monitor.methodStarting();",
+ " try {",
+ " return module.produceString();",
+ " } finally {",
+ " monitor.methodFinished();",
+ " }",
+ " }",
+ " }, executor);",
+ " }",
+ "}");
+ assertAbout(javaSource())
+ .that(moduleFile)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(factoryFile);
+ }
+
+ private static final JavaFileObject QUALIFIER_A =
+ JavaFileObjects.forSourceLines("test.QualifierA",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierA {}");
+ private static final JavaFileObject QUALIFIER_B =
+ JavaFileObjects.forSourceLines("test.QualifierB",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier @interface QualifierB {}");
+
+ @Test public void producesMethodMultipleQualifiers() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class TestModule {",
+ " @Produces @QualifierA @QualifierB abstract String produceString() {",
+ " return \"\";",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, QUALIFIER_A, QUALIFIER_B))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java
new file mode 100644
index 0000000..a8e39b2
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+
+@RunWith(JUnit4.class)
+public class ProductionComponentProcessorTest {
+ @Test public void componentOnConcreteClass() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "final class NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnEnum() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "enum NotAComponent {",
+ " INSTANCE",
+ "}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void componentOnAnnotation() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent",
+ "@interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void nonModuleModule() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(modules = Object.class)",
+ "interface NotAComponent {}");
+ assertAbout(javaSource()).that(componentFile)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("is not annotated with @Module or @ProducerModule");
+ }
+
+ @Test public void simpleComponent() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "import javax.inject.Inject;",
+ "",
+ "final class TestClass {",
+ " static final class C {",
+ " @Inject C() {}",
+ " }",
+ "",
+ " interface A {}",
+ " interface B {}",
+ "",
+ " @Module",
+ " static final class BModule {",
+ " @Provides B b(C c) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " static final class AModule {",
+ " @Produces ListenableFuture<A> a(B b) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {AModule.class, BModule.class})",
+ " interface SimpleComponent {",
+ " ListenableFuture<A> a();",
+ " }",
+ "}");
+ JavaFileObject generatedComponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerTestClass_SimpleComponent",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.internal.InstanceFactory;",
+ "import dagger.internal.SetFactory;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor.Factory;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "import test.TestClass.A;",
+ "import test.TestClass.AModule;",
+ "import test.TestClass.B;",
+ "import test.TestClass.BModule;",
+ "import test.TestClass.SimpleComponent;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerTestClass_SimpleComponent implements SimpleComponent {",
+ " private Provider<SimpleComponent> simpleComponentProvider;",
+ " private Provider<Set<Factory>> setOfFactoryContribution1Provider;",
+ " private Provider<Set<Factory>> setOfFactoryProvider;",
+ " private Provider<ProductionComponentMonitor> monitorProvider;",
+ " private Provider<B> bProvider;",
+ " private Producer<A> aProducer;",
+ "",
+ " private DaggerTestClass_SimpleComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.simpleComponentProvider = InstanceFactory.<SimpleComponent>create(this);",
+ " this.setOfFactoryContribution1Provider =",
+ " TestClass$SimpleComponent_MonitoringModule_DefaultSetOfFactoriesFactory",
+ " .create();",
+ " this.setOfFactoryProvider = SetFactory.create(setOfFactoryContribution1Provider);",
+ " this.monitorProvider =",
+ " TestClass$SimpleComponent_MonitoringModule_MonitorFactory.create(",
+ " builder.testClass$SimpleComponent_MonitoringModule,",
+ " simpleComponentProvider,",
+ " setOfFactoryProvider);",
+ " this.bProvider = TestClass$BModule_BFactory.create(",
+ " builder.bModule, TestClass$C_Factory.create());",
+ " this.aProducer = new TestClass$AModule_AFactory(",
+ " builder.aModule,",
+ " builder.executor,",
+ " monitorProvider,",
+ " Producers.producerFromProvider(bProvider));",
+ " }",
+ "",
+ " @Override",
+ " public ListenableFuture<A> a() {",
+ " return aProducer.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private TestClass$SimpleComponent_MonitoringModule",
+ " testClass$SimpleComponent_MonitoringModule;",
+ " private BModule bModule;",
+ " private AModule aModule;",
+ " private Executor executor;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public SimpleComponent build() {",
+ " if (testClass$SimpleComponent_MonitoringModule == null) {",
+ " this.testClass$SimpleComponent_MonitoringModule =",
+ " new TestClass$SimpleComponent_MonitoringModule();",
+ " }",
+ " if (bModule == null) {",
+ " this.bModule = new BModule();",
+ " }",
+ " if (aModule == null) {",
+ " this.aModule = new AModule();",
+ " }",
+ " if (executor == null) {",
+ " throw new IllegalStateException(Executor.class.getCanonicalName()",
+ " + \" must be set\");",
+ " }",
+ " return new DaggerTestClass_SimpleComponent(this);",
+ " }",
+ "",
+ " public Builder aModule(AModule aModule) {",
+ " if (aModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.aModule = aModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder bModule(BModule bModule) {",
+ " if (bModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.bModule = bModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder testClass$SimpleComponent_MonitoringModule(",
+ " TestClass$SimpleComponent_MonitoringModule",
+ " testClass$SimpleComponent_MonitoringModule) {",
+ " if (testClass$SimpleComponent_MonitoringModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.testClass$SimpleComponent_MonitoringModule =",
+ " testClass$SimpleComponent_MonitoringModule;",
+ " return this;",
+ " }",
+ "",
+ " public Builder executor(Executor executor) {",
+ " if (executor == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.executor = executor;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(generatedComponent);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java
new file mode 100644
index 0000000..6fc8716
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ProductionGraphValidationTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.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;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/**
+ * Unit tests for {@link BindingGraphValidator} that exercise producer-specific logic.
+ */
+@RunWith(JUnit4.class)
+public class ProductionGraphValidationTest {
+ @Test public void componentWithUnprovidedInput() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(modules = FooModule.class)",
+ "interface MyComponent {",
+ " ListenableFuture<Foo> getFoo();",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.FooModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "class Foo {}",
+ "class Bar {}",
+ "",
+ "@ProducerModule",
+ "class FooModule {",
+ " @Produces Foo foo(Bar bar) {",
+ " return null;",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(Arrays.asList(module, component))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("test.Bar cannot be provided without an @Inject constructor or from "
+ + "an @Provides- or @Produces-annotated method.")
+ .in(component).onLine(8);
+ }
+
+ @Test public void componentProductionWithNoDependencyChain() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @ProductionComponent()",
+ " interface AComponent {",
+ " ListenableFuture<A> getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A cannot be provided without an @Provides- or @Produces-annotated method.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(11);
+ }
+
+ @Test public void provisionDependsOnProduction() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ " interface B {}",
+ "",
+ " @Module",
+ " final class AModule {",
+ " @Provides A a(B b) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " final class BModule {",
+ " @Produces ListenableFuture<B> b() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {AModule.class, BModule.class})",
+ " interface AComponent {",
+ " ListenableFuture<A> getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A is a provision, which cannot depend on a production.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(30);
+ }
+
+ @Test public void provisionEntryPointDependsOnProduction() {
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @ProducerModule",
+ " final class AModule {",
+ " @Produces ListenableFuture<A> a() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = AModule.class)",
+ " interface AComponent {",
+ " A getA();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A is a provision entry-point, which cannot depend on a production.";
+ assertAbout(javaSource()).that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError).in(component).onLine(20);
+ }
+
+ @Test
+ public void monitoringDependsOnUnboundType() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @Module",
+ " final class MonitoringModule {",
+ " @Provides(type = SET)",
+ " ProductionComponentMonitor.Factory monitorFactory(A unbound) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " final class StringModule {",
+ " @Produces ListenableFuture<String> str() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {MonitoringModule.class, StringModule.class})",
+ " interface StringComponent {",
+ " ListenableFuture<String> getString();",
+ " }",
+ "}");
+ String expectedError =
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.";
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(33);
+ }
+
+ @Test
+ public void monitoringDependsOnProduction() {
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestClass",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.ProductionComponent;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "",
+ "import static dagger.Provides.Type.SET;",
+ "",
+ "final class TestClass {",
+ " interface A {}",
+ "",
+ " @Module",
+ " final class MonitoringModule {",
+ " @Provides(type = SET) ProductionComponentMonitor.Factory monitorFactory(A a) {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProducerModule",
+ " final class StringModule {",
+ " @Produces A a() {",
+ " return null;",
+ " }",
+ "",
+ " @Produces ListenableFuture<String> str() {",
+ " return null;",
+ " }",
+ " }",
+ "",
+ " @ProductionComponent(modules = {MonitoringModule.class, StringModule.class})",
+ " interface StringComponent {",
+ " ListenableFuture<String> getString();",
+ " }",
+ "}");
+ String expectedError =
+ "java.util.Set<dagger.producers.monitoring.ProductionComponentMonitor.Factory> is a"
+ + " provision, which cannot depend on a production.";
+ assertAbout(javaSource())
+ .that(component)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(expectedError)
+ .in(component)
+ .onLine(36);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java
new file mode 100644
index 0000000..6bf0c9e
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/RepeatedModuleValidationTest.java
@@ -0,0 +1,121 @@
+package dagger.internal.codegen;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public class RepeatedModuleValidationTest {
+ private static final JavaFileObject MODULE_FILE =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+
+ @Test
+ public void moduleRepeatedInSubcomponentFactoryMethod() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent newTestSubcomponent(TestModule module);",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("This module is present in test.TestComponent.")
+ .in(componentFile)
+ .onLine(7)
+ .atColumn(51);
+ }
+
+ @Test
+ public void moduleRepeatedInSubcomponentBuilderMethod() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Builder testModule(TestModule testModule);",
+ " TestSubcomponent build();",
+ " }",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent.Builder newTestSubcomponentBuilder();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ // TODO(gak): assert about the warning when we have that ability
+ }
+
+ @Test
+ public void moduleRepeatedButNotPassed() {
+ JavaFileObject subcomponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface TestSubcomponent {",
+ "}");
+ JavaFileObject componentFile =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " TestSubcomponent newTestSubcomponent();",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(MODULE_FILE, subcomponentFile, componentFile))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
new file mode 100644
index 0000000..6311a90
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+/** Tests for {@link dagger.Subcomponent.Builder} validation. */
+@RunWith(JUnit4.class)
+public class SubcomponentBuilderValidationTest {
+
+ private static final ErrorMessages.SubcomponentBuilderMessages MSGS =
+ new ErrorMessages.SubcomponentBuilderMessages();
+
+ @Test
+ public void testRefSubcomponentAndSubBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent child();",
+ " ChildComponent.Builder builder();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
+ "test.ChildComponent", "[child(), builder()]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testRefSubBuilderTwiceFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder builder1();",
+ " ChildComponent.Builder builder2();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOneRefToSubcomponent(),
+ "test.ChildComponent", "[builder1(), builder2()]"))
+ .in(componentFile);
+ }
+
+ @Test
+ public void testMoreThanOneBuilderFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " static interface Builder1 {",
+ " ChildComponent build();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " static interface Builder2 {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.moreThanOne(),
+ "[test.ChildComponent.Builder1, test.ChildComponent.Builder2]"))
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderGenericsFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder<T> {",
+ " ChildComponent build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.generics())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderNotInComponentFails() {
+ JavaFileObject builder = JavaFileObjects.forSourceLines("test.Builder",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent.Builder",
+ "interface Builder {}");
+ assertAbout(javaSource()).that(builder)
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeInComponent())
+ .in(builder);
+ }
+
+ @Test
+ public void testBuilderMissingBuildMethodFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder1 build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.missingBuildMethod())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testPrivateBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " private interface Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.isPrivate())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testNonStaticBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " abstract class Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeStatic())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testNonAbstractBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static class Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeAbstract())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderOneCxtorWithArgsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static abstract class Builder {",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderMoreThanOneCxtorFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " static abstract class Builder {",
+ " Builder() {}",
+ " Builder(String unused) {}",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.cxtorOnlyOneAndNoArgs())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderEnumFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " enum Builder {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.mustBeClassOrInterface())
+ .in(childComponentFile);
+ }
+
+ @Test
+ public void testBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " String build();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.buildMustReturnComponentType())
+ .in(childComponentFile).onLine(9);
+ }
+
+ @Test
+ public void testInheritedBuilderBuildReturnsWrongTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " String build();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedBuildMustReturnComponentType(), "build"))
+ .in(childComponentFile).onLine(12);
+ }
+
+ @Test
+ public void testTwoBuildMethodsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " ChildComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(String.format(MSGS.twoBuildMethods(), "build()"))
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testInheritedTwoBuildMethodsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " ChildComponent create();",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedTwoBuildMethods(), "create()", "build()"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testMoreThanOneArgFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " Builder set(String s, Integer i);",
+ " Builder set(Number n, Double d);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(childComponentFile).onLine(10)
+ .and().withErrorContaining(MSGS.methodsMustTakeOneArg())
+ .in(childComponentFile).onLine(11);
+ }
+
+ @Test
+ public void testInheritedMoreThanOneArgFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " Builder set1(String s, Integer i);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustTakeOneArg(),
+ "set1(java.lang.String,java.lang.Integer)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " String set(Integer i);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMustReturnVoidOrBuilder())
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testInheritedSetterReturningNonVoidOrBuilderFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " String set(Integer i);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMustReturnVoidOrBuilder(),
+ "set(java.lang.Integer)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testGenericsOnSetterMethodFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
+ .in(childComponentFile).onLine(10);
+ }
+
+ @Test
+ public void testGenericsOnInheritedSetterMethodFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent {",
+ " ChildComponent build();",
+ " <T> Builder set(T t);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent {}",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
+ .in(childComponentFile).onLine(13);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " void set1(String s);",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(java.lang.String), set2(java.lang.String)]"))
+ .in(childComponentFile).onLine(8);
+ }
+
+ @Test
+ public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "abstract class ChildComponent {",
+ " interface Parent<T> {",
+ " void set1(T t);",
+ " }",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder extends Parent<String> {",
+ " ChildComponent build();",
+ " void set2(String s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.manyMethodsForType(),
+ "java.lang.String", "[set1(T), set2(java.lang.String)]"))
+ .in(childComponentFile).onLine(12);
+ }
+
+ @Test
+ public void testExtraSettersFails() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent build();",
+ " void set1(String s);",
+ " void set2(Integer s);",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ String.format(MSGS.extraSetters(),
+ "[void test.ChildComponent.Builder.set1(String),"
+ + " void test.ChildComponent.Builder.set2(Integer)]"))
+ .in(childComponentFile).onLine(8);
+
+ }
+
+ @Test
+ public void testMissingSettersFail() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " TestModule(String unused) {}",
+ " @Provides String s() { return null; }",
+ "}");
+ JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test2Module {",
+ " @Provides Integer i() { return null; }",
+ "}");
+ JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class Test3Module {",
+ " Test3Module(String unused) {}",
+ " @Provides Double d() { return null; }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent.Builder build();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {TestModule.class, Test2Module.class, Test3Module.class})",
+ "interface ChildComponent {",
+ " String string();",
+ " Integer integer();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " ChildComponent create();",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(ImmutableList.of(moduleFile,
+ module2File,
+ module3File,
+ componentFile,
+ childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ // Ignores Test2Module because we can construct it ourselves.
+ // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
+ String.format(MSGS.missingSetters(), "[test.TestModule, test.Test3Module]"))
+ .in(childComponentFile).onLine(11);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java b/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java
new file mode 100644
index 0000000..d47c328
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+
+@RunWith(JUnit4.class)
+public final class SubcomponentValidationTest {
+ @Test public void factoryMethod_missingModulesWithParameters() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ModuleWithParameters.class)",
+ "interface ChildComponent {",
+ " Object object();",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ModuleWithParameters",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class ModuleWithParameters {",
+ " private final Object object;",
+ "",
+ " ModuleWithParameters(Object object) {",
+ " this.object = object;",
+ " }",
+ "",
+ " @Provides Object object() {",
+ " return object;",
+ " }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.ChildComponent requires modules which have no visible default constructors. "
+ + "Add the following modules as parameters to this method: "
+ + "test.ModuleWithParameters")
+ .in(componentFile).onLine(7);
+ }
+
+ @Test public void factoryMethod_nonModuleParameter() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(String someRandomString);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "Subcomponent factory methods may only accept modules, but java.lang.String is not.")
+ .in(componentFile).onLine(7).atColumn(43);
+ }
+
+ @Test public void factoryMethod_duplicateParameter() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(TestModule testModule1, TestModule testModule2);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "A module may only occur once an an argument in a Subcomponent factory method, "
+ + "but test.TestModule was already passed.")
+ .in(componentFile).onLine(7).atColumn(71);
+ }
+
+ @Test public void factoryMethod_superflouousModule() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "final class TestModule {}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent(TestModule testModule);",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface ChildComponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "test.TestModule is present as an argument to the test.ChildComponent factory method, but "
+ + "is not one of the modules used to implement the subcomponent.")
+ .in(componentFile).onLine(7);
+ }
+
+ @Test public void missingBinding() {
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " @Provides String provideString(int i) {",
+ " return Integer.toString(i);",
+ " }",
+ "}");
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface TestComponent {",
+ " ChildComponent newChildComponent();",
+ "}");
+ JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface ChildComponent {",
+ " String getString();",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(moduleFile, componentFile, childComponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining(
+ "java.lang.Integer cannot be provided without an @Inject constructor or from an "
+ + "@Provides-annotated method");
+ }
+
+ @Test public void subcomponentOnConcreteType() {
+ JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.NotASubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "final class NotASubcomponent {}");
+ assertAbout(javaSources()).that(ImmutableList.of(subcomponentFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("interface");
+ }
+
+ @Test public void scopeMismatch() {
+ JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Component",
+ "@Singleton",
+ "interface ParentComponent {",
+ " ChildComponent childComponent();",
+ "}");
+ JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Object getObject();",
+ "}");
+ JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Singleton;",
+ "",
+ "@Module",
+ "final class ChildModule {",
+ " @Provides @Singleton Object provideObject() { return null; }",
+ "}");
+ assertAbout(javaSources()).that(ImmutableList.of(componentFile, subcomponentFile, moduleFile))
+ .processedWith(new ComponentProcessor())
+ .failsToCompile()
+ .withErrorContaining("@Singleton");
+ }
+
+ @Test
+ public void delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent() {
+ JavaFileObject parentComponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.ParentComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface ParentComponent {",
+ " ChildComponent childComponent();",
+ " Dep1 getDep1();",
+ " Dep2 getDep2();",
+ "}");
+ JavaFileObject childComponentFile =
+ JavaFileObjects.forSourceLines(
+ "test.ChildComponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface ChildComponent {",
+ " Object getObject();",
+ "}");
+ JavaFileObject childModuleFile =
+ JavaFileObjects.forSourceLines(
+ "test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class ChildModule {",
+ " @Provides Object provideObject(A a) { return null; }",
+ "}");
+ JavaFileObject aFile =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject public A(NeedsDep1 a, Dep1 b, Dep2 c) { }",
+ " @Inject public void methodA() { }",
+ "}");
+ JavaFileObject needsDep1File =
+ JavaFileObjects.forSourceLines(
+ "test.NeedsDep1",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class NeedsDep1 {",
+ " @Inject public NeedsDep1(Dep1 d) { }",
+ "}");
+ JavaFileObject dep1File =
+ JavaFileObjects.forSourceLines(
+ "test.Dep1",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep1 {",
+ " @Inject public Dep1() { }",
+ " @Inject public void dep1Method() { }",
+ "}");
+ JavaFileObject dep2File =
+ JavaFileObjects.forSourceLines(
+ "test.Dep2",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class Dep2 {",
+ " @Inject public Dep2() { }",
+ " @Inject public void dep2Method() { }",
+ "}");
+
+ JavaFileObject componentGeneratedFile =
+ JavaFileObjects.forSourceLines(
+ "DaggerParentComponent",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerParentComponent implements ParentComponent {",
+ " private MembersInjector<Dep1> dep1MembersInjector;",
+ " private Provider<Dep1> dep1Provider;",
+ " private MembersInjector<Dep2> dep2MembersInjector;",
+ " private Provider<Dep2> dep2Provider;",
+ "",
+ " private DaggerParentComponent(Builder builder) { ",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() { ",
+ " return new Builder();",
+ " }",
+ "",
+ " public static ParentComponent create() { ",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) { ",
+ " this.dep1MembersInjector = Dep1_MembersInjector.create();",
+ " this.dep1Provider = Dep1_Factory.create(dep1MembersInjector);",
+ " this.dep2MembersInjector = Dep2_MembersInjector.create();",
+ " this.dep2Provider = Dep2_Factory.create(dep2MembersInjector);",
+ " }",
+ "",
+ " @Override",
+ " public Dep1 getDep1() { ",
+ " return dep1Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public Dep2 getDep2() { ",
+ " return dep2Provider.get();",
+ " }",
+ "",
+ " @Override",
+ " public ChildComponent childComponent() { ",
+ " return new ChildComponentImpl();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private Builder() { ",
+ " }",
+ " ",
+ " public ParentComponent build() { ",
+ " return new DaggerParentComponent(this);",
+ " }",
+ " }",
+ "",
+ " private final class ChildComponentImpl implements ChildComponent {",
+ " private final ChildModule childModule;",
+ " private MembersInjector<A> aMembersInjector;",
+ " private Provider<NeedsDep1> needsDep1Provider;",
+ " private Provider<A> aProvider;",
+ " private Provider<Object> provideObjectProvider;",
+ " ",
+ " private ChildComponentImpl() { ",
+ " this.childModule = new ChildModule();",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() { ",
+ " this.aMembersInjector = A_MembersInjector.create();",
+ " this.needsDep1Provider = NeedsDep1_Factory.create(",
+ " DaggerParentComponent.this.dep1Provider);",
+ " this.aProvider = A_Factory.create(",
+ " aMembersInjector,",
+ " needsDep1Provider,",
+ " DaggerParentComponent.this.dep1Provider,",
+ " DaggerParentComponent.this.dep2Provider);",
+ " this.provideObjectProvider = ChildModule_ProvideObjectFactory.create(",
+ " childModule, aProvider);",
+ " }",
+ " ",
+ " @Override",
+ " public Object getObject() { ",
+ " return provideObjectProvider.get();",
+ " }",
+ " }",
+ "}");
+ assertAbout(javaSources())
+ .that(
+ ImmutableList.of(
+ parentComponentFile,
+ childComponentFile,
+ childModuleFile,
+ aFile,
+ needsDep1File,
+ dep1File,
+ dep2File))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and()
+ .generatesSources(componentGeneratedFile);
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java b/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java
new file mode 100644
index 0000000..d7f4451
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/ValidationReportTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.ValidationReport.Builder;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertAbout;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
+
+@RunWith(JUnit4.class)
+public class ValidationReportTest {
+ private static final JavaFileObject TEST_CLASS_FILE =
+ JavaFileObjects.forSourceLines("test.TestClass",
+ "package test;",
+ "",
+ "final class TestClass {}");
+
+ @Test
+ public void basicReport() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ Builder<TypeElement> reportBuilder =
+ ValidationReport.about(getTypeElement("test.TestClass"));
+ reportBuilder.addError("simple error");
+ reportBuilder.build().printMessagesTo(processingEnv.getMessager());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ @Test
+ public void messageOnDifferentElement() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ Builder<TypeElement> reportBuilder =
+ ValidationReport.about(getTypeElement("test.TestClass"));
+ reportBuilder.addError("simple error", getTypeElement(String.class));
+ reportBuilder.build().printMessagesTo(processingEnv.getMessager());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("[java.lang.String] simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ @Test
+ public void subreport() {
+ assertAbout(javaSource())
+ .that(TEST_CLASS_FILE)
+ .processedWith(
+ new SimpleTestProcessor() {
+ @Override
+ void test() {
+ Builder<TypeElement> reportBuilder =
+ ValidationReport.about(getTypeElement("test.TestClass"));
+ reportBuilder.addError("simple error");
+ ValidationReport<TypeElement> parentReport =
+ ValidationReport.about(getTypeElement(String.class))
+ .addSubreport(reportBuilder.build())
+ .build();
+ assertThat(parentReport.isClean()).isFalse();
+ parentReport.printMessagesTo(processingEnv.getMessager());
+ }
+ })
+ .failsToCompile()
+ .withErrorContaining("simple error")
+ .in(TEST_CLASS_FILE)
+ .onLine(3);
+ }
+
+ private static abstract class SimpleTestProcessor extends AbstractProcessor {
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ return ImmutableSet.of("*");
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ test();
+ return false;
+ }
+
+ protected final TypeElement getTypeElement(Class<?> clazz) {
+ return getTypeElement(clazz.getCanonicalName());
+ }
+
+ protected final TypeElement getTypeElement(String canonicalName) {
+ return processingEnv.getElementUtils().getTypeElement(canonicalName);
+ }
+
+ abstract void test();
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java
new file mode 100644
index 0000000..eff01b8
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/ClassNameTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.codegen.writer.ClassNameTest.OuterClass.InnerClass;
+import java.util.Map;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class ClassNameTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ @Test public void bestGuessForString_simpleClass() {
+ assertThat(ClassName.bestGuessFromString(String.class.getName()))
+ .isEqualTo(ClassName.create("java.lang", "String"));
+ }
+
+ static class OuterClass {
+ static class InnerClass {}
+ }
+
+ @Test public void bestGuessForString_nestedClass() {
+ assertThat(ClassName.bestGuessFromString(Map.Entry.class.getCanonicalName()))
+ .isEqualTo(ClassName.create("java.util", ImmutableList.of("Map"), "Entry"));
+ assertThat(ClassName.bestGuessFromString(OuterClass.InnerClass.class.getCanonicalName()))
+ .isEqualTo(
+ ClassName.create("dagger.internal.codegen.writer",
+ ImmutableList.of("ClassNameTest", "OuterClass"), "InnerClass"));
+ }
+
+ @Test public void bestGuessForString_defaultPackage() {
+ assertThat(ClassName.bestGuessFromString("SomeClass"))
+ .isEqualTo(ClassName.create("", "SomeClass"));
+ assertThat(ClassName.bestGuessFromString("SomeClass.Nested"))
+ .isEqualTo(ClassName.create("", ImmutableList.of("SomeClass"), "Nested"));
+ assertThat(ClassName.bestGuessFromString("SomeClass.Nested.EvenMore"))
+ .isEqualTo(ClassName.create("", ImmutableList.of("SomeClass", "Nested"), "EvenMore"));
+ }
+
+ @Test public void bestGuessForString_confusingInput() {
+ try {
+ ClassName.bestGuessFromString("com.test.$");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ ClassName.bestGuessFromString("com.test.LooksLikeAClass.pkg");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ ClassName.bestGuessFromString("!@#$gibberish%^&*");
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ @Test public void classNameFromTypeElement() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(Object.class.getCanonicalName());
+ assertThat(ClassName.fromTypeElement(element).canonicalName())
+ .isEqualTo("java.lang.Object");
+ }
+
+ @Test public void peerNamed_topLevelClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(ClassNameTest.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.Foo");
+ }
+
+ @Test public void peerNamed_nestedClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(OuterClass.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.ClassNameTest.Foo");
+ }
+
+ @Test public void peerNamed_deeplyNestedClass() {
+ Elements elements = compilationRule.getElements();
+ TypeElement element = elements.getTypeElement(InnerClass.class.getCanonicalName());
+ ClassName className = ClassName.fromTypeElement(element);
+ ClassName peerName = className.peerNamed("Foo");
+ assertThat(peerName.canonicalName())
+ .isEqualTo("dagger.internal.codegen.writer.ClassNameTest.OuterClass.Foo");
+ }
+
+ @Test public void fromClass_NonNestedClass() {
+ ClassName className = ClassName.fromClass(ClassNameTest.class);
+ assertThat(className.canonicalName()).isEqualTo(
+ "dagger.internal.codegen.writer.ClassNameTest");
+ }
+
+ @Test public void fromClass_NestedClass() {
+ ClassName className = ClassName.fromClass(InnerClass.class);
+ assertThat(className.canonicalName()).isEqualTo(
+ "dagger.internal.codegen.writer.ClassNameTest.OuterClass.InnerClass");
+ }
+
+ @Test public void fromClass_classFileName() {
+ ClassName className = ClassName.fromClass(InnerClass.class);
+ assertThat(className.classFileName('_')).isEqualTo("ClassNameTest_OuterClass_InnerClass");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java
new file mode 100644
index 0000000..e775f74
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/JavaWriterTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class JavaWriterTest {
+ @Test public void referencedAndDeclaredSimpleName() {
+ JavaWriter javaWriter = JavaWriter.inPackage("test");
+ ClassWriter topClass = javaWriter.addClass("Top");
+ topClass.addNestedClass("Middle").addNestedClass("Bottom");
+ topClass.addField(ClassName.create("some.other.pkg", "Bottom"), "field");
+ assertThat(topClass.toString()).doesNotContain("import some.other.pkg.Bottom;");
+ }
+}
diff --git a/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java b/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java
new file mode 100644
index 0000000..ec82e96
--- /dev/null
+++ b/compiler/src/test/java/dagger/internal/codegen/writer/TypeNamesTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.internal.codegen.writer;
+
+import com.google.testing.compile.CompilationRule;
+import java.nio.charset.Charset;
+import java.util.Set;
+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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class TypeNamesTest {
+ @Rule public final CompilationRule compilation = new CompilationRule();
+
+ private TypeElement getElement(Class<?> clazz) {
+ return compilation.getElements().getTypeElement(clazz.getCanonicalName());
+ }
+
+ private TypeMirror getType(Class<?> clazz) {
+ return getElement(clazz).asType();
+ }
+
+ @Test
+ public void forTypeMirror_basicTypes() {
+ assertThat(TypeNames.forTypeMirror(getType(Object.class)))
+ .isEqualTo(ClassName.fromClass(Object.class));
+ assertThat(TypeNames.forTypeMirror(getType(Charset.class)))
+ .isEqualTo(ClassName.fromClass(Charset.class));
+ assertThat(TypeNames.forTypeMirror(getType(TypeNamesTest.class)))
+ .isEqualTo(ClassName.fromClass(TypeNamesTest.class));
+ }
+
+ @Test
+ public void forTypeMirror_parameterizedType() {
+ DeclaredType setType =
+ compilation.getTypes().getDeclaredType(getElement(Set.class), getType(Object.class));
+ assertThat(TypeNames.forTypeMirror(setType))
+ .isEqualTo(ParameterizedTypeName.create(Set.class, ClassName.fromClass(Object.class)));
+ }
+
+ @Test
+ public void forTypeMirror_typeVariables() {
+ TypeMirror setType = getType(Set.class);
+ assertThat(TypeNames.forTypeMirror(setType))
+ .isEqualTo(ParameterizedTypeName.create(Set.class, TypeVariableName.named("E")));
+ }
+
+ @Test
+ public void forTypeMirror_primitive() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.BOOLEAN)))
+ .isEqualTo(PrimitiveName.BOOLEAN);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.BYTE)))
+ .isEqualTo(PrimitiveName.BYTE);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.SHORT)))
+ .isEqualTo(PrimitiveName.SHORT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.INT)))
+ .isEqualTo(PrimitiveName.INT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.LONG)))
+ .isEqualTo(PrimitiveName.LONG);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.CHAR)))
+ .isEqualTo(PrimitiveName.CHAR);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.FLOAT)))
+ .isEqualTo(PrimitiveName.FLOAT);
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getPrimitiveType(TypeKind.DOUBLE)))
+ .isEqualTo(PrimitiveName.DOUBLE);
+ }
+
+ @Test
+ public void forTypeMirror_arrays() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getArrayType(getType(Object.class))))
+ .isEqualTo(new ArrayTypeName(ClassName.fromClass(Object.class)));
+ }
+
+ @Test
+ public void forTypeMirror_void() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getNoType(TypeKind.VOID)))
+ .isEqualTo(VoidName.VOID);
+ }
+
+ @Test
+ public void forTypeMirror_null() {
+ assertThat(TypeNames.forTypeMirror(compilation.getTypes().getNullType()))
+ .isEqualTo(NullName.NULL);
+ }
+}
diff --git a/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java
new file mode 100644
index 0000000..58fa263
--- /dev/null
+++ b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java
@@ -0,0 +1,143 @@
+/**
+ * Copyright (C) 2013 Google, Inc.
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.tests.integration.operation;
+
+import com.google.testing.compile.JavaFileObjects;
+import dagger.internal.codegen.ComponentProcessor;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
+import static java.util.Arrays.asList;
+
+@RunWith(JUnit4.class)
+public final class PrimitiveInjectionTest {
+
+ // TODO(cgruber): Use @test.ForTest to qualify primitives once qualifier equivalence is working.
+ /*
+ JavaFileObject annotation = JavaFileObjects.forSourceLines("test.ForTest",
+ "package test;",
+ "import javax.inject.Qualifier;",
+ "@Qualifier",
+ "public @interface ForTest {",
+ "}");
+ */
+
+ // TODO(cgruber): Expand test to support more primitive types when b/15512877 is fixed.
+ JavaFileObject primitiveInjectable = JavaFileObjects.forSourceLines("test.PrimitiveInjectable",
+ "package test;",
+ "import javax.inject.Inject;",
+ "class PrimitiveInjectable {",
+ " @Inject PrimitiveInjectable(int ignored) {}",
+ "}");
+
+ JavaFileObject primitiveModule = JavaFileObjects.forSourceLines("test.PrimitiveModule",
+ "package test;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "@Module",
+ "class PrimitiveModule {",
+ " @Provides int primitiveInt() { return Integer.MAX_VALUE; }",
+ "}");
+
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.PrimitiveComponent",
+ "package test;",
+ "import dagger.Component;",
+ "import dagger.Provides;",
+ "@Component(modules = PrimitiveModule.class)",
+ "interface PrimitiveComponent {",
+ " int primitiveInt();",
+ " PrimitiveInjectable primitiveInjectable();",
+ "}");
+
+ JavaFileObject expectedComponent = JavaFileObjects.forSourceLines(
+ "test.DaggerPrimitiveComponent",
+ "package test;",
+ "",
+ "import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
+ "",
+ "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
+ "public final class DaggerPrimitiveComponent implements PrimitiveComponent {",
+ " private Provider<Integer> primitiveIntProvider;",
+ " private Provider<PrimitiveInjectable> primitiveInjectableProvider;",
+ "",
+ " private DaggerPrimitiveComponent(Builder builder) {",
+ " assert builder != null;",
+ " initialize(builder);",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static PrimitiveComponent create() {",
+ " return builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.primitiveIntProvider =",
+ " PrimitiveModule_PrimitiveIntFactory.create(builder.primitiveModule);",
+ " this.primitiveInjectableProvider =",
+ " PrimitiveInjectable_Factory.create(primitiveIntProvider);",
+ " }",
+ "",
+ " @Override",
+ " public int primitiveInt() {",
+ " return primitiveIntProvider.get();",
+ " }",
+ "",
+ " @Override",
+ " public PrimitiveInjectable primitiveInjectable() {",
+ " return primitiveInjectableProvider.get();",
+ " }",
+ "",
+ " public static final class Builder {",
+ " private PrimitiveModule primitiveModule;",
+ "",
+ " private Builder() {",
+ " }",
+ "",
+ " public PrimitiveComponent build() {",
+ " if (primitiveModule == null) {",
+ " this.primitiveModule = new PrimitiveModule();",
+ " }",
+ " return new DaggerPrimitiveComponent(this);",
+ " }",
+ "",
+ " public Builder primitiveModule(PrimitiveModule primitiveModule) {",
+ " if (primitiveModule == null) {",
+ " throw new NullPointerException();",
+ " }",
+ " this.primitiveModule = primitiveModule;",
+ " return this;",
+ " }",
+ " }",
+ "}");
+
+ @Test public void primitiveArrayTypesAllInjected() {
+ assert_().about(javaSources())
+ .that(asList(component, primitiveInjectable, primitiveModule))
+ .processedWith(new ComponentProcessor())
+ .compilesWithoutError()
+ .and().generatesSources(expectedComponent);
+ }
+}
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..eab9dd8
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger</artifactId>
+ <name>Dagger</name>
+
+ <properties>
+ <!-- Runtime must remain Java6 to support android. -->
+ <java.version>1.6</java.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.8</version><!-- 1.9+ requires JDK7 on the build machine -->
+ <executions>
+ <execution>
+ <id>sniff-api</id>
+ <goals><goal>check</goal></goals>
+ </execution>
+ </executions>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java16</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>dagger.internal:dagger.internal.*</excludePackageNames>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/core/src/main/java/dagger/Component.java b/core/src/main/java/dagger/Component.java
new file mode 100644
index 0000000..7d72401
--- /dev/null
+++ b/core/src/main/java/dagger/Component.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Qualifier;
+import javax.inject.Scope;
+import javax.inject.Singleton;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotates an interface or abstract class for which a fully-formed, dependency-injected
+ * implementation is to be generated from a set of {@linkplain #modules}. The generated class will
+ * have the name of the type annotated with {@code @Component} prepended with {@code Dagger}. For
+ * example, {@code @Component interface MyComponent {...}} will produce an implementation named
+ * {@code DaggerMyComponent}.
+ *
+ * <a name="component-methods">
+ * <h2>Component methods</h2>
+ * </a>
+ *
+ * <p>Every type annotated with {@code @Component} must contain at least one abstract component
+ * method. Component methods may have any name, but must have signatures that conform to either
+ * {@linkplain Provider provision} or {@linkplain MembersInjector members-injection} contracts.
+ *
+ * <a name="provision-methods">
+ * <h3>Provision methods</h3>
+ * </a>
+ *
+ * <p>Provision methods have no parameters and return an {@link Inject injected} or
+ * {@link Provides provided} type. Each method may have a {@link Qualifier} annotation as well. The
+ * following are all valid provision method declarations: <pre><code>
+ * SomeType getSomeType();
+ * {@literal Set<SomeType>} getSomeTypes();
+ * {@literal @PortNumber} int getPortNumber();
+ * </code></pre>
+ *
+ * <p>Provision methods, like typical {@link Inject injection} sites, may use {@link Provider} or
+ * {@link Lazy} to more explicitly control provision requests. A {@link Provider} allows the user
+ * of the component to request provision any number of times by calling {@link Provider#get}. A
+ * {@link Lazy} will only ever request a single provision, but will defer it until the first call to
+ * {@link Lazy#get}. The following provision methods all request provision of the same type, but
+ * each implies different semantics: <pre><code>
+ * SomeType getSomeType();
+ * {@literal Provider<SomeType>} getSomeTypeProvider();
+ * {@literal Lazy<SomeType>} getLazySomeType();
+ * </code></pre>
+ *
+ * <a name="members-injection-methods">
+ * <h3>Members-injection methods</h3>
+ * </a>
+ *
+ * <p>Members-injection methods have a single parameter and inject dependencies into each of the
+ * {@link Inject}-annotated fields and methods of the passed instance. A members-injection method
+ * may be void or return its single parameter as a convenience for chaining. The following are all
+ * valid members-injection method declarations: <pre><code>
+ * void injectSomeType(SomeType someType);
+ * SomeType injectAndReturnSomeType(SomeType someType);
+ * </code></pre>
+ *
+ * <p>A method with no parameters that returns a {@link MembersInjector} is equivalent to a members
+ * injection method. Calling {@link MembersInjector#injectMembers} on the returned object will
+ * perform the same work as a members injection method. For example: <pre><code>
+ * {@literal MembersInjector<SomeType>} getSomeTypeMembersInjector();
+ * </code></pre>
+ *
+ * <h4>A note about covariance</h4>
+ *
+ * <p>While a members-injection method for a type will accept instances of its subtypes, only
+ * {@link Inject}-annotated members of the parameter type and its supertypes will be injected;
+ * members of subtypes will not. For example, given the following types, only {@code a} and
+ * {@code b} will be injected into an instance of {@code Child} when it is passed to the
+ * members-injection method {@code injectSelf(Self instance)}: <pre><code>
+ * class Parent {
+ * {@literal @}Inject A a;
+ * }
+ *
+ * class Self extends Parent {
+ * {@literal @}Inject B b;
+ * }
+ *
+ * class Child extends Self {
+ * {@literal @}Inject C c;
+ * }
+ * </code></pre>
+ *
+ * <a name="instantiation">
+ * <h2>Instantiation</h2>
+ * </a>
+ *
+ * <p>Component implementations are primarily instantiated via a generated
+ * <a href="http://en.wikipedia.org/wiki/Builder_pattern">builder</a>. An instance of the builder
+ * is obtained using the {@code builder()} method on the component implementation.
+ * If a nested {@code @Component.Builder} type exists in the component, the {@code builder()}
+ * method will return a generated implementation of that type. If no nested
+ * {@code @Component.Builder} exists, the returned builder has a method to set each of the
+ * {@linkplain #modules} and component {@linkplain #dependencies} named with the
+ * <a href="http://en.wikipedia.org/wiki/CamelCase">lower camel case</a> version of the module
+ * or dependency type. Each component dependency and module without a visible default constructor
+ * must be set explicitly, but any module with a default or no-args constructor accessible to the
+ * component implementation may be elided. This is an example usage of a component builder:
+ * <pre><code>
+ * public static void main(String[] args) {
+ * OtherComponent otherComponent = ...;
+ * MyComponent component = DaggerMyComponent.builder()
+ * // required because component dependencies must be set
+ * .otherComponent(otherComponent)
+ * // required because FlagsModule has constructor parameters
+ * .flagsModule(new FlagsModule(args))
+ * // may be elided because a no-args constructor is visible
+ * .myApplicationModule(new MyApplicationModule())
+ * .build();
+ * }
+ * </code></pre>
+ *
+ * <p>In the case that a component has no component dependencies and only no-arg modules, the
+ * generated component will also have a factory method {@code create()}.
+ * {@code SomeComponent.create()} and {@code SomeComponent.builder().build()} are both valid and
+ * equivalent.
+ *
+ * <a name="scope">
+ * <h2>Scope</h2>
+ * </a>
+ *
+ * <p>Each Dagger component can be associated with a scope by annotating it with the
+ * {@linkplain Scope scope annotation}. The component implementation ensures that there is only one
+ * provision of each scoped binding per instance of the component. If the component declares a
+ * scope, it may only contain unscoped bindings or bindings of that scope anywhere in the graph. For
+ * example: <pre><code>
+ * {@literal @}Singleton {@literal @}Component
+ * interface MyApplicationComponent {
+ * // this component can only inject types using unscoped or {@literal @}Singleton bindings
+ * }
+ * </code></pre>
+ *
+ * <p>In order to get the proper behavior associated with a scope annotation, it is the caller's
+ * responsibility to instantiate new component instances when appropriate. A {@link Singleton}
+ * component, for instance, should only be instantiated once per application, while a
+ * {@code RequestScoped} component should be instantiated once per request. Because components are
+ * self-contained implementations, exiting a scope is as simple as dropping all references to the
+ * component instance.
+ *
+ * <a name="component-relationships">
+ * <h2>Component relationships</h2>
+ * </a>
+ *
+ * <p>While there is much utility in isolated components with purely unscoped bindings, many
+ * applications will call for multiple components with multiple scopes to interact. Dagger provides
+ * two mechanisms for relating components.
+ *
+ * <a name="subcomponents">
+ * <h3>Subcomponents</h3>
+ * </a>
+ *
+ * <p>The simplest way to relate two components is by declaring a {@link Subcomponent}. A
+ * subcomponent behaves exactly like a component, but has its implementation generated within
+ * a parent component or subcomponent. That relationship allows the subcomponent implementation to
+ * inherit the <em>entire</em> binding graph from its parent when it is declared. For that reason,
+ * a subcomponent isn't evaluated for completeness until it is associated with a parent.
+ *
+ * <p>Subcomponents are declared via a factory method on a parent component or subcomponent. The
+ * method may have any name, but must return the subcomponent. The factory method's parameters may
+ * be any number of the subcomponent's modules, but must at least include those without visible
+ * no-arg constructors. The following is an example of a factory method that creates a
+ * request-scoped subcomponent from a singleton-scoped parent: <pre><code>
+ * {@literal @}Singleton {@literal @}Component
+ * interface ApplicationComponent {
+ * // component methods...
+ *
+ * RequestComponent newRequestComponent(RequestModule requestModule);
+ * }
+ * </code></pre>
+ *
+ * <a name="component-dependencies">
+ * <h3>Component dependencies</h3>
+ * </a>
+ *
+ * <p>While subcomponents are the simplest way to compose subgraphs of bindings, subcomponents are
+ * tightly coupled with the parents; they may use any binding defined by their ancestor component
+ * and subcomponents. As an alternative, components can use bindings only from another
+ * <em>component interface</em> by declaring a {@linkplain #dependencies component dependency}. When
+ * a type is used as a component dependency, each <a href="#provision-methods">provision method</a>
+ * on the dependency is bound as a provider. Note that <em>only</em> the bindings exposed as
+ * provision methods are available through component dependencies.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
+@Target(TYPE)
+@Documented
+public @interface Component {
+ /**
+ * A list of classes annotated with {@link Module} whose bindings are used to generate the
+ * component implementation. Note that through the use of {@link Module#includes} the full set of
+ * modules used to implement the component may include more modules that just those listed here.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A list of types that are to be used as <a href="#component-dependencies">component
+ * dependencies</a>.
+ */
+ Class<?>[] dependencies() default {};
+
+ /**
+ * A builder for a component. Components may have a single nested static abstract class or
+ * interface annotated with {@code @Component.Builder}. If they do, then the component's
+ * generated builder will match the API in the type. Builders must follow some rules:
+ * <ul>
+ * <li> A single abstract method with no arguments must exist, and must return the component.
+ * (This is typically the {@code build()} method.)
+ * <li> All other abstract methods must take a single argument and must return void,
+ * the Builder type, or a supertype of the builder.
+ * <li> Each component dependency <b>must</b> have an abstract setter method.
+ * <li> Each module dependency that Dagger can't instantiate itself (e.g, the module
+ * doesn't have a visible no-args constructor) <b>must</b> have an abstract setter method.
+ * Other module dependencies (ones that Dagger can instantiate) are allowed, but not required.
+ * <li> Non-abstract methods are allowed, but ignored as far as validation and builder generation
+ * are concerned.
+ * </ul>
+ *
+ * For example, this could be a valid Component with a Builder: <pre><code>
+ * {@literal @}Component(modules = {BackendModule.class, FrontendModule.class})
+ * interface MyComponent {
+ * MyWidget myWidget();
+ *
+ * {@literal @}Component.Builder
+ * interface Builder {
+ * MyComponent build();
+ * Builder backendModule(BackendModule bm);
+ * Builder frontendModule(FrontendModule fm);
+ * }
+ * }</code></pre>
+ */
+ @Target(TYPE)
+ @Documented
+ @interface Builder {}
+}
diff --git a/core/src/main/java/dagger/Lazy.java b/core/src/main/java/dagger/Lazy.java
new file mode 100644
index 0000000..e04cc03
--- /dev/null
+++ b/core/src/main/java/dagger/Lazy.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+/**
+ * A handle to a lazily-computed value. Each {@code Lazy} computes its value on
+ * the first call to {@code get()} and remembers that same value for all
+ * subsequent calls to {@code get()}.
+ *
+ * <p>{@code null} is not a supported value. Implementations of {@code Lazy}
+ * are expected to throw {@link NullPointerException} if the computed value is
+ * {@code null}.
+ *
+ * <h2>Example</h2>
+ * The differences between <strong>direct injection</strong>, <strong>provider
+ * injection</strong> and <strong>lazy injection</strong> are best demonstrated
+ * with an example. Start with a module that computes a different integer for
+ * each use:<pre><code>
+ * {@literal @Module}
+ * final class CounterModule {
+ * int next = 100;
+ *
+ * {@literal @Provides} Integer provideInteger() {
+ * System.out.println("computing...");
+ * return next++;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <h3>Direct Injection</h3>
+ * This class injects that integer and prints it 3 times:<pre><code>
+ * final class DirectCounter {
+ * {@literal @Inject} Integer value;
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(value);
+ * System.out.println(value);
+ * System.out.println(value);
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code DirectCounter} and invoking {@code print()} reveals that
+ * the value is computed <i>before</i> it is required:<pre><code>
+ * computing...
+ * printing...
+ * 100
+ * 100
+ * 100
+ * </code></pre>
+ *
+ * <h3>Provider Injection</h3>
+ * This class injects a {@linkplain javax.inject.Provider provider} for the
+ * integer. It calls {@code Provider.get()} 3 times and prints each result:
+ * <pre><code>
+ * final class ProviderCounter {
+ * {@literal @Inject Provider<Integer> provider;}
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(provider.get());
+ * System.out.println(provider.get());
+ * System.out.println(provider.get());
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code ProviderCounter} and invoking {@code print()} shows that
+ * a new value is computed each time {@code Provider.get()} is used:<pre><code>
+ * printing...
+ * computing...
+ * 100
+ * computing...
+ * 101
+ * computing...
+ * 102
+ * </code></pre>
+ *
+ * <h3>Lazy Injection</h3>
+ * This class injects a {@code Lazy} for the integer. Like the provider above,
+ * it calls {@code Lazy.get()} 3 times and prints each result:<pre><code>
+ * final class LazyCounter {
+ * {@literal @Inject Lazy<Integer> lazy;}
+ *
+ * void print() {
+ * System.out.println("printing...");
+ * System.out.println(lazy.get());
+ * System.out.println(lazy.get());
+ * System.out.println(lazy.get());
+ * }
+ * }
+ * </code></pre>
+ * Injecting a {@code LazyCounter} and invoking {@code print()} shows that a new
+ * value is computed immediately before it is needed. The same value is returned
+ * for all subsequent uses:<pre><code>
+ * printing...
+ * computing...
+ * 100
+ * 100
+ * 100
+ * </code></pre>
+ *
+ * <h3>Lazy != Singleton</h3>
+ * Note that each injected {@code Lazy} is independent, and remembers its value
+ * in isolation of other {@code Lazy} instances. In this example, two {@code
+ * LazyCounter} objects are created and {@code print()} is called on each:
+ * <pre><code>
+ * final class LazyCounters {
+ * {@literal @Inject} LazyCounter counter1;
+ * {@literal @Inject} LazyCounter counter2;
+ *
+ * void print() {
+ * counter1.print();
+ * counter2.print();
+ * }
+ * }
+ * </code></pre>
+ * The output demonstrates that each {@code Lazy} works independently:
+ * <pre><code>
+ * printing...
+ * computing...
+ * 100
+ * 100
+ * 100
+ * printing...
+ * computing...
+ * 101
+ * 101
+ * 101
+ * </code></pre>
+ * Use {@link javax.inject.Singleton @Singleton} to share one instance among all
+ * clients, and {@code Lazy} for lazy computation in a single client.
+ */
+public interface Lazy<T> {
+ /**
+ * Return the underlying value, computing the value if necessary. All calls to
+ * the same {@code Lazy} instance will return the same result.
+ *
+ * @throws NullPointerException if the computed value is {@code null}.
+ */
+ T get();
+}
diff --git a/core/src/main/java/dagger/MapKey.java b/core/src/main/java/dagger/MapKey.java
new file mode 100644
index 0000000..106c001
--- /dev/null
+++ b/core/src/main/java/dagger/MapKey.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.Map;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Identifies annotation types that are used to associate keys with values returned by
+ * {@linkplain Provides provider methods} in order to compose a {@linkplain Provides.Type#MAP map}.
+ *
+ * <p>Every provider method annotated with {@code @Provides(type = MAP)} must also have an
+ * annotation that identifies the key for that map entry. That annotation's type must be annotated
+ * with {@code @MapKey}.
+ *
+ * <p>Typically, the key annotation has a single member, whose value is used as the map key.
+ *
+ * <p>For example, to add an entry to a {@code Map<SomeEnum, Integer>} with key
+ * {@code SomeEnum.FOO}, you could use an annotation called {@code @SomeEnumKey}:
+ *
+ * <pre><code>
+ * {@literal @}MapKey
+ * {@literal @}interface SomeEnumKey {
+ * SomeEnum value();
+ * }
+ *
+ * {@literal @}Module
+ * class SomeModule {
+ * {@literal @}Provides(type = MAP)
+ * {@literal @}SomeEnumKey(SomeEnum.FOO)
+ * Integer provideFooValue() {
+ * return 2;
+ * }
+ * }
+ *
+ * class SomeInjectedType {
+ * {@literal @}Inject
+ * SomeInjectedType(Map<SomeEnum, Integer> map) {
+ * assert map.get(SomeEnum.FOO) == 2;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>If {@code unwrapValue} is true, the annotation's single member can be any type except an
+ * array.
+ *
+ * <p>See {@link dagger.mapkeys} for standard unwrapped map key annotations for keys that are boxed
+ * primitives, strings, or classes.
+ *
+ * <h2>Annotations as keys</h2>
+ *
+ * <p>If {@link #unwrapValue} is false, then the annotation itself is used as the map key. For
+ * example, to add an entry to a {@code Map<MyMapKey, Integer>} map:
+ *
+ * <pre><code>
+ * {@literal @}MapKey(unwrapValue = false)
+ * {@literal @}interface MyMapKey {
+ * String someString();
+ * MyEnum someEnum();
+ * }
+ *
+ * {@literal @}Module
+ * class SomeModule {
+ * {@literal @}Provides(type = MAP)
+ * {@literal @}MyMapKey(someString = "foo", someEnum = BAR)
+ * Integer provideFooBarValue() {
+ * return 2;
+ * }
+ * }
+ *
+ * class SomeInjectedType {
+ * {@literal @}Inject
+ * SomeInjectedType(Map<MyMapKey, Integer> map) {
+ * assert map.get(new MyMapKeyImpl("foo", MyEnum.BAR)) == 2;
+ * }
+ * }
+ * </code></pre>
+ *
+ * <p>(Note that there must be a class {@code MyMapKeyImpl} that implements {@code MyMapKey} in
+ * order to call {@link Map#get(Object)} on the provided map.)
+ *
+ */
+@Documented
+@Target(ANNOTATION_TYPE)
+@Retention(RUNTIME)
+@Beta
+public @interface MapKey {
+ /**
+ * True to use the value of the single member of the annotated annotation as the map key; false
+ * to use the annotation instance as the map key.
+ *
+ * <p>If true, the single member must not be an array.
+ */
+ boolean unwrapValue() default true;
+}
diff --git a/core/src/main/java/dagger/MembersInjector.java b/core/src/main/java/dagger/MembersInjector.java
new file mode 100644
index 0000000..d0de7f3
--- /dev/null
+++ b/core/src/main/java/dagger/MembersInjector.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Square, Inc.
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+/**
+ * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
+ * presence or absence of an injectable constructor.
+ *
+ * @param <T> type to inject members of
+ *
+ * @author Bob Lee
+ * @author Jesse Wilson
+ * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept
+ * {@code null})
+ */
+public interface MembersInjector<T> {
+
+ /**
+ * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
+ * absence of an injectable constructor.
+ *
+ * <p>Whenever the object graph creates an instance, it performs this injection automatically
+ * (after first performing constructor injection), so if you're able to let the object graph
+ * create all your objects for you, you'll never need to use this method.
+ *
+ * @param instance into which members are to be injected
+ * @throws NullPointerException if {@code instance} is {@code null}
+ */
+ void injectMembers(T instance);
+}
diff --git a/core/src/main/java/dagger/Module.java b/core/src/main/java/dagger/Module.java
new file mode 100644
index 0000000..05f0f3a
--- /dev/null
+++ b/core/src/main/java/dagger/Module.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a class that contributes to the object graph.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Module {
+ /**
+ * Additional {@code @Module}-annotated classes from which this module is
+ * composed. The de-duplicated contributions of the modules in
+ * {@code includes}, and of their inclusions recursively, are all contributed
+ * to the object graph.
+ */
+ Class<?>[] includes() default {};
+}
diff --git a/core/src/main/java/dagger/Provides.java b/core/src/main/java/dagger/Provides.java
new file mode 100644
index 0000000..741a54a
--- /dev/null
+++ b/core/src/main/java/dagger/Provides.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ * Copyright (C) 2012 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotates methods of a module to create a provider method binding. The
+ * method's return type is bound to its returned value. The object graph will
+ * pass dependencies to the method as parameters.
+ *
+ * @author Bob Lee
+ */
+@Documented @Target(METHOD) @Retention(RUNTIME)
+public @interface Provides {
+ /** The type of binding into which the return type of the annotated method contributes. */
+ enum Type {
+ /**
+ * The method is the only one which can produce the value for the specified return type. This
+ * is the default behavior.
+ */
+ UNIQUE,
+
+ /**
+ * The method's return type forms the generic type argument of a {@code Set<T>}, and the
+ * returned value is contributed to the set. The object graph will pass dependencies to the
+ * method as parameters. The {@code Set<T>} produced from the accumulation of values will be
+ * immutable.
+ *
+ */
+ SET,
+
+ /**
+ * Like {@link #SET}, except the method's return type is {@code Set<T>}, where any values are
+ * contributed to the set. An example use is to provide a default empty set binding, which is
+ * otherwise not possible using {@link #SET}.
+ *
+ */
+ SET_VALUES,
+
+ /**
+ * The method's return type forms the type argument for the value of a
+ * {@code Map<K, Provider<V>>}, and the combination of the annotated key and the returned value
+ * is contributed to the map as a key/value pair. The {@code Map<K, Provider<V>>} produced from
+ * the accumulation of values will be immutable.
+ *
+ */
+ @Beta
+ MAP;
+ }
+
+ Type type() default Type.UNIQUE;
+}
diff --git a/core/src/main/java/dagger/Subcomponent.java b/core/src/main/java/dagger/Subcomponent.java
new file mode 100644
index 0000000..988f17b
--- /dev/null
+++ b/core/src/main/java/dagger/Subcomponent.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * A subcomponent that inherits the bindings from a parent {@link Component} or
+ * {@link Subcomponent}. The details of how to associate a subcomponent with a parent are described
+ * in the documentation for {@link Component}.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
+@Target(TYPE)
+@Documented
+public @interface Subcomponent {
+ /**
+ * A list of classes annotated with {@link Module} whose bindings are used to generate the
+ * subcomponent implementation. Note that through the use of {@link Module#includes} the full set
+ * of modules used to implement the subcomponent may include more modules that just those listed
+ * here.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A builder for a subcomponent. This follows all the rules of {@link Component.Builder}, except
+ * it must appear in classes annotated with {@link Subcomponent} instead of {@code Component}.
+ * Components can have methods that return a {@link Subcomponent.Builder}-annotated type,
+ * allowing the user to set modules on the subcomponent using their defined API.
+ */
+ @Target(TYPE)
+ @Documented
+ @interface Builder {}
+}
diff --git a/core/src/main/java/dagger/internal/Beta.java b/core/src/main/java/dagger/internal/Beta.java
new file mode 100644
index 0000000..a0a82c6
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Beta.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.Documented;
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Signifies that a public API (public class, method or field) is subject to
+ * incompatible changes, or even removal, in a future release. An API bearing
+ * this annotation is exempt from any compatibility guarantees made by its
+ * containing library. Note that the presence of this annotation implies nothing
+ * about the quality or performance of the API in question, only the fact that
+ * it is not "API-frozen."
+ */
+@Documented
+@Retention(SOURCE)
+public @interface Beta {}
diff --git a/core/src/main/java/dagger/internal/Collections.java b/core/src/main/java/dagger/internal/Collections.java
new file mode 100644
index 0000000..55f26eb
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Collections.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+
+final class Collections {
+ /**
+ * The maximum value for a signed 32-bit integer that is equal to a power of 2.
+ */
+ private static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
+
+ private Collections() {
+ }
+
+ /**
+ * Creates a {@link LinkedHashSet} instance, with a high enough "initial capacity" that it
+ * <em>should</em> hold {@code expectedSize} elements without growth.
+ */
+ static <E> LinkedHashSet<E> newLinkedHashSetWithExpectedSize(int expectedSize) {
+ return new LinkedHashSet<E>(calculateInitialCapacity(expectedSize));
+ }
+
+ /**
+ * Creates a {@link LinkedHashMap} instance, with a high enough "initial capacity" that it
+ * <em>should</em> hold {@code expectedSize} elements without growth.
+ */
+ static <K, V> LinkedHashMap<K, V> newLinkedHashMapWithExpectedSize(int expectedSize) {
+ return new LinkedHashMap<K, V>(calculateInitialCapacity(expectedSize));
+ }
+
+ private static int calculateInitialCapacity(int expectedSize) {
+ if (expectedSize < 3) {
+ return expectedSize + 1;
+ }
+ if (expectedSize < MAX_POWER_OF_TWO) {
+ // This is the calculation used in JDK8 to resize when a putAll
+ // happens; it seems to be the most conservative calculation we
+ // can make. 0.75 is the default load factor.
+ return (int) (expectedSize / 0.75F + 1.0F);
+ }
+ return Integer.MAX_VALUE; // any large value
+ }
+}
diff --git a/core/src/main/java/dagger/internal/DelegateFactory.java b/core/src/main/java/dagger/internal/DelegateFactory.java
new file mode 100644
index 0000000..d1e864d
--- /dev/null
+++ b/core/src/main/java/dagger/internal/DelegateFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 javax.inject.Provider;
+
+/**
+ * A DelegateFactory that is used to stitch Provider/Lazy indirection based dependency cycles.
+ *
+ * @since 2.0.1
+ */
+public final class DelegateFactory<T> implements Factory<T> {
+ private Provider<T> delegate;
+
+ @Override
+ public T get() {
+ if (delegate == null) {
+ throw new IllegalStateException();
+ }
+ return delegate.get();
+ }
+
+ public void setDelegatedProvider(Provider<T> delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException();
+ }
+ if (this.delegate != null) {
+ throw new IllegalStateException();
+ }
+ this.delegate = delegate;
+ }
+}
+
diff --git a/core/src/main/java/dagger/internal/DoubleCheckLazy.java b/core/src/main/java/dagger/internal/DoubleCheckLazy.java
new file mode 100644
index 0000000..d0f1028
--- /dev/null
+++ b/core/src/main/java/dagger/internal/DoubleCheckLazy.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 dagger.Lazy;
+import javax.inject.Provider;
+
+/**
+ * A basic {@link Lazy} implementation that memoizes the value returned from a {@link Provider}
+ * using the double-check idiom described in Effective Java 2: Item 71.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+// TODO(gak): Unify the duplicated code between this and ScopedProvider.
+public final class DoubleCheckLazy<T> implements Lazy<T> {
+ private static final Object UNINITIALIZED = new Object();
+
+ private final Provider<T> provider;
+ private volatile Object instance = UNINITIALIZED;
+
+ private DoubleCheckLazy(Provider<T> provider) {
+ assert provider != null;
+ this.provider = provider;
+ }
+
+ @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
+ @Override
+ public T get() {
+ // to suppress it.
+ Object result = instance;
+ if (result == UNINITIALIZED) {
+ synchronized (this) {
+ result = instance;
+ if (result == UNINITIALIZED) {
+ instance = result = provider.get();
+ }
+ }
+ }
+ return (T) result;
+ }
+
+ public static <T> Lazy<T> create(Provider<T> provider) {
+ if (provider == null) {
+ throw new NullPointerException();
+ }
+ if (provider instanceof Lazy) {
+ @SuppressWarnings("unchecked")
+ final Lazy<T> lazy = (Lazy<T>) provider;
+ // Avoids memoizing a value that is already memoized.
+ // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
+ // are different types using covariant return on get(). Right now this is used with
+ // ScopedProvider<T> exclusively, which is implemented such that P and L are always the same
+ // so it will be fine for that case.
+ return lazy;
+ }
+ return new DoubleCheckLazy<T>(provider);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/Factory.java b/core/src/main/java/dagger/internal/Factory.java
new file mode 100644
index 0000000..3e2774c
--- /dev/null
+++ b/core/src/main/java/dagger/internal/Factory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Scope;
+
+/**
+ * An {@linkplain Scope unscoped} {@link Provider}. While a {@link Provider} <i>may<i> apply
+ * scoping semantics while providing an instance, a factory implementation is guaranteed to exercise
+ * the binding logic ({@link Inject} constructors, {@link Provides} methods) upon each call to
+ * {@link #get}.
+ *
+ * <p>Note that while subsequent calls to {@link #get} will create new instances for bindings such
+ * as those created by {@link Inject} constructors, a new instance is not guaranteed by all
+ * bindings. For example, {@link Provides} methods may be implemented in ways that return the same
+ * instance for each call.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public interface Factory<T> extends Provider<T> {
+}
diff --git a/core/src/main/java/dagger/internal/InstanceFactory.java b/core/src/main/java/dagger/internal/InstanceFactory.java
new file mode 100644
index 0000000..59b1fcb
--- /dev/null
+++ b/core/src/main/java/dagger/internal/InstanceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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} implementation that returns a single instance for all invocations of
+ * {@link #get}.
+ *
+ * <p>Note that while this is a {@link Factory} implementation, and thus unscoped, each call to
+ * {@link #get} will always return the same instance. As such, any scoping applied to this factory
+ * is redundant and unnecessary. However, using this with the {@link ScopedProvider} is valid and
+ * may be desired for testing or contractual guarantees.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class InstanceFactory<T> implements Factory<T> {
+ public static <T> Factory<T> create(T instance) {
+ if (instance == null) {
+ throw new NullPointerException();
+ }
+ return new InstanceFactory<T>(instance);
+ }
+
+ private final T instance;
+
+ private InstanceFactory(T instance) {
+ this.instance = instance;
+ }
+
+ @Override
+ public T get() {
+ return instance;
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MapFactory.java b/core/src/main/java/dagger/internal/MapFactory.java
new file mode 100644
index 0000000..4dac126
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MapFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.Map;
+import java.util.Map.Entry;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashMapWithExpectedSize;
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
+ * {@code Map<K, V>} when calling {@link #get} (as specified by {@link Factory}).
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ *
+ */
+public final class MapFactory<K, V> implements Factory<Map<K, V>> {
+ private final Map<K, Provider<V>> contributingMap;
+
+ private MapFactory(Map<K, Provider<V>> map) {
+ this.contributingMap = unmodifiableMap(map);
+ }
+
+ /**
+ * Returns a new MapFactory.
+ */
+ public static <K, V> MapFactory<K, V> create(Provider<Map<K, Provider<V>>> mapProviderFactory) {
+ Map<K, Provider<V>> map = mapProviderFactory.get();
+ return new MapFactory<K, V>(map);
+ }
+
+ /**
+ * Returns a {@code Map<K, V>} whose iteration order is that of the elements
+ * given by each of the providers, which are invoked in the order given at creation.
+ */
+ @Override
+ public Map<K, V> get() {
+ Map<K, V> result = newLinkedHashMapWithExpectedSize(contributingMap.size());
+ for (Entry<K, Provider<V>> entry: contributingMap.entrySet()) {
+ result.put(entry.getKey(), entry.getValue().get());
+ }
+ return unmodifiableMap(result);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MapProviderFactory.java b/core/src/main/java/dagger/internal/MapProviderFactory.java
new file mode 100644
index 0000000..00c0fd3
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MapProviderFactory.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.LinkedHashMap;
+import java.util.Map;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashMapWithExpectedSize;
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
+ * {@code Map<K, Provider<V>>} when calling {@link #get} (as specified by {@link Factory}).
+ *
+ * @author Chenying Hou
+ * @since 2.0
+ *
+ */
+public final class MapProviderFactory<K, V> implements Factory<Map<K, Provider<V>>> {
+ private final Map<K, Provider<V>> contributingMap;
+
+ /**
+ * Returns a new {@link Builder}
+ */
+ public static <K, V> Builder<K, V> builder(int size) {
+ return new Builder<K, V>(size);
+ }
+
+ private MapProviderFactory(LinkedHashMap<K, Provider<V>> contributingMap) {
+ this.contributingMap = unmodifiableMap(contributingMap);
+ }
+
+ /**
+ * Returns a {@code Map<K, Provider<V>>} whose iteration order is that of the elements
+ * given by each of the providers, which are invoked in the order given at creation.
+ *
+ */
+ @Override
+ public Map<K, Provider<V>> get() {
+ return this.contributingMap;
+ }
+
+ /**
+ * A builder to help build the {@link MapProviderFactory}
+ */
+ public static final class Builder<K, V> {
+ private final LinkedHashMap<K, Provider<V>> mapBuilder;
+
+ private Builder(int size) {
+ // TODO(user): consider which way to initialize mapBuilder is better
+ this.mapBuilder = newLinkedHashMapWithExpectedSize(size);
+ }
+
+ /**
+ * Returns a new {@link MapProviderFactory}
+ */
+ public MapProviderFactory<K, V> build() {
+ return new MapProviderFactory<K, V>(this.mapBuilder);
+ }
+
+ /**
+ * Associate k with providerOfValue in {@code Builder}
+ */
+ public Builder<K, V> put(K key, Provider<V> providerOfValue) {
+ if (key == null) {
+ throw new NullPointerException("The key is null");
+ }
+ if (providerOfValue == null) {
+ throw new NullPointerException("The provider of the value is null");
+ }
+
+ this.mapBuilder.put(key, providerOfValue);
+ return this;
+ }
+ }
+}
diff --git a/core/src/main/java/dagger/internal/MembersInjectors.java b/core/src/main/java/dagger/internal/MembersInjectors.java
new file mode 100644
index 0000000..ee4c7b4
--- /dev/null
+++ b/core/src/main/java/dagger/internal/MembersInjectors.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 dagger.MembersInjector;
+import javax.inject.Inject;
+
+/**
+ * Basic {@link MembersInjector} implementations used by the framework.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class MembersInjectors {
+ /**
+ * Returns a {@link MembersInjector} implementation that injects no members
+ *
+ * <p>Note that there is no verification that the type being injected does not have {@link Inject}
+ * members, so care should be taken to ensure appropriate use.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> MembersInjector<T> noOp() {
+ return (MembersInjector<T>) NoOpMembersInjector.INSTANCE;
+ }
+
+ private static enum NoOpMembersInjector implements MembersInjector<Object> {
+ INSTANCE;
+
+ @Override public void injectMembers(Object instance) {
+ if (instance == null) {
+ throw new NullPointerException();
+ }
+ }
+ }
+
+ /**
+ * Returns a {@link MembersInjector} that delegates to the {@link MembersInjector} of its
+ * supertype. This is useful for cases where a type is known not to have its own {@link Inject}
+ * members, but must still inject members on its supertype(s).
+ *
+ * <p>Note that there is no verification that the type being injected does not have {@link Inject}
+ * members, so care should be taken to ensure appropriate use.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> MembersInjector<T> delegatingTo(MembersInjector<? super T> delegate) {
+ return (MembersInjector<T>) delegate;
+ }
+
+ private MembersInjectors() {}
+}
diff --git a/core/src/main/java/dagger/internal/ScopedProvider.java b/core/src/main/java/dagger/internal/ScopedProvider.java
new file mode 100644
index 0000000..b25db38
--- /dev/null
+++ b/core/src/main/java/dagger/internal/ScopedProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 dagger.Lazy;
+import javax.inject.Provider;
+
+/**
+ * A {@link Provider} implementation that memoizes the result of a {@link Factory} instance.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class ScopedProvider<T> implements Provider<T>, Lazy<T> {
+ private static final Object UNINITIALIZED = new Object();
+
+ private final Factory<T> factory;
+ private volatile Object instance = UNINITIALIZED;
+
+ private ScopedProvider(Factory<T> factory) {
+ assert factory != null;
+ this.factory = factory;
+ }
+
+ @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
+ @Override
+ public T get() {
+ // double-check idiom from EJ2: Item 71
+ Object result = instance;
+ if (result == UNINITIALIZED) {
+ synchronized (this) {
+ result = instance;
+ if (result == UNINITIALIZED) {
+ instance = result = factory.get();
+ }
+ }
+ }
+ return (T) result;
+ }
+
+ /** Returns a new scoped provider for the given factory. */
+ public static <T> Provider<T> create(Factory<T> factory) {
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ return new ScopedProvider<T>(factory);
+ }
+}
diff --git a/core/src/main/java/dagger/internal/SetFactory.java b/core/src/main/java/dagger/internal/SetFactory.java
new file mode 100644
index 0000000..9b73e79
--- /dev/null
+++ b/core/src/main/java/dagger/internal/SetFactory.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Provider;
+
+import static dagger.internal.Collections.newLinkedHashSetWithExpectedSize;
+import static java.util.Collections.unmodifiableSet;
+
+/**
+ * A {@link Factory} implementation used to implement {@link Set} bindings. This factory always
+ * returns a new {@link Set} instance for each call to {@link #get} (as required by {@link Factory})
+ * whose elements are populated by subsequent calls to their {@link Provider#get} methods.
+ *
+ * @author Gregory Kick
+ * @since 2.0
+ */
+public final class SetFactory<T> implements Factory<Set<T>> {
+ /**
+ * A message for NPEs that trigger on bad argument lists.
+ */
+ private static final String ARGUMENTS_MUST_BE_NON_NULL =
+ "SetFactory.create() requires its arguments to be non-null";
+
+ /**
+ * Returns the supplied factory. If there's just one factory, there's no need to wrap it or its
+ * result.
+ */
+ public static <T> Factory<Set<T>> create(Factory<Set<T>> factory) {
+ assert factory != null : ARGUMENTS_MUST_BE_NON_NULL;
+ return factory;
+ }
+
+ /**
+ * Returns a new factory that creates {@link Set} instances that form the union of the given
+ * {@link Provider} instances. Callers must not modify the providers array after invoking this
+ * method; no copy is made.
+ */
+ public static <T> Factory<Set<T>> create(
+ @SuppressWarnings("unchecked") Provider<Set<T>>... providers) {
+ assert providers != null : ARGUMENTS_MUST_BE_NON_NULL;
+
+ List<Provider<Set<T>>> contributingProviders = Arrays.asList(providers);
+
+ assert !contributingProviders.contains(null)
+ : "Codegen error? Null within provider list.";
+ assert !hasDuplicates(contributingProviders)
+ : "Codegen error? Duplicates in the provider list";
+
+ return new SetFactory<T>(contributingProviders);
+ }
+
+ /**
+ * Returns true if at least one pair of items in (@code original) are equals.
+ */
+ private static boolean hasDuplicates(List<? extends Object> original) {
+ Set<Object> asSet = new HashSet<Object>(original);
+ return original.size() != asSet.size();
+ }
+
+ private final List<Provider<Set<T>>> contributingProviders;
+
+ private SetFactory(List<Provider<Set<T>>> contributingProviders) {
+ this.contributingProviders = contributingProviders;
+ }
+
+ /**
+ * Returns a {@link Set} whose iteration order is that of the elements given by each of the
+ * providers, which are invoked in the order given at creation.
+ *
+ * @throws NullPointerException if any of the delegate {@link Set} instances or elements therein
+ * are {@code null}
+ */
+ @Override
+ public Set<T> get() {
+ int size = 0;
+
+ // Profiling revealed that this method was a CPU-consuming hotspot in some applications, so
+ // these loops were changed to use c-style for. Versus enhanced for-each loops, C-style for is
+ // faster for ArrayLists, at least through Java 8.
+
+ List<Set<T>> providedSets = new ArrayList<Set<T>>(contributingProviders.size());
+ for (int i = 0, c = contributingProviders.size(); i < c; i++) {
+ Provider<Set<T>> provider = contributingProviders.get(i);
+ Set<T> providedSet = provider.get();
+ if (providedSet == null) {
+ throw new NullPointerException(provider + " returned null");
+ }
+ providedSets.add(providedSet);
+ size += providedSet.size();
+ }
+
+ Set<T> result = newLinkedHashSetWithExpectedSize(size);
+ for (int i = 0, c = providedSets.size(); i < c; i++) {
+ for (T element : providedSets.get(i)) {
+ if (element == null) {
+ throw new NullPointerException("a null element was provided");
+ }
+ result.add(element);
+ }
+ }
+ return unmodifiableSet(result);
+ }
+}
diff --git a/core/src/main/java/dagger/mapkeys/ClassKey.java b/core/src/main/java/dagger/mapkeys/ClassKey.java
new file mode 100644
index 0000000..21497c6
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/ClassKey.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * A {@link MapKey} annotation for maps with {@code Class<?>} keys.
+ *
+ * <p>If your map's keys can be constrained, consider using a custom annotation instead, with a
+ * member whose type is {@code Class<? extends Something>}.
+ */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface ClassKey {
+ Class<?> value();
+}
\ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/IntKey.java b/core/src/main/java/dagger/mapkeys/IntKey.java
new file mode 100644
index 0000000..011b49f
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/IntKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@code int} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface IntKey {
+ int value();
+}
\ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/LongKey.java b/core/src/main/java/dagger/mapkeys/LongKey.java
new file mode 100644
index 0000000..183b74d
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/LongKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@code long} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface LongKey {
+ long value();
+}
\ No newline at end of file
diff --git a/core/src/main/java/dagger/mapkeys/StringKey.java b/core/src/main/java/dagger/mapkeys/StringKey.java
new file mode 100644
index 0000000..7455a9b
--- /dev/null
+++ b/core/src/main/java/dagger/mapkeys/StringKey.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package dagger.mapkeys;
+
+import dagger.MapKey;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/** A {@link MapKey} annotation for maps with {@link String} keys. */
+@Documented
+@Target(METHOD)
+@MapKey
+public @interface StringKey {
+ String value();
+}
\ No newline at end of file
diff --git a/core/src/main/java/dagger/package-info.java b/core/src/main/java/dagger/package-info.java
new file mode 100644
index 0000000..e5cc67f
--- /dev/null
+++ b/core/src/main/java/dagger/package-info.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 public API for the <a href="http://google.github.io/dagger/">Dagger
+ * 2</a> dependency injection framework. By building upon
+ * <a href="https://jcp.org/en/jsr/detail?id=330">JSR 330</a>, Dagger 2 provides an
+ * annotation-driven API for dependency injection whose implementation is entirely generated at
+ * compile time by <a href="http://en.wikipedia.org/wiki/Java_annotation#Processing">annotation
+ * processors</a>.
+ *
+ * <p>The entry point into the API is the {@link Component}, which annotates abstract types for
+ * Dagger 2 to implement. The dependency graph is configured using using annotations such as
+ * {@link Module}, {@link Provides} and {@link javax.inject.Inject}.
+ *
+ * <p>{@code dagger.internal.codegen.ComponentProcessor} is the processor responsible for generating
+ * the implementation. Dagger uses the annotation procesor
+ * {@linkplain java.util.ServiceLoader service loader} to automatically configure the processor, so
+ * explict build configuration shouldn't be necessary.
+ */
+package dagger;
diff --git a/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java b/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java
new file mode 100644
index 0000000..579e040
--- /dev/null
+++ b/core/src/test/java/dagger/internal/DoubleCheckLazyTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Uninterruptibles;
+import dagger.Lazy;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static org.junit.Assert.fail;
+
+@RunWith(JUnit4.class)
+public class DoubleCheckLazyTest {
+ @Test public void get() throws Exception {
+ int numThreads = 10;
+ ExecutorService executor = Executors.newFixedThreadPool(numThreads);
+
+ final CountDownLatch latch = new CountDownLatch(numThreads);
+ LatchedProvider provider = new LatchedProvider(latch);
+ final Lazy<Object> lazy = DoubleCheckLazy.create(provider);
+
+ List<Callable<Object>> tasks = Lists.newArrayListWithCapacity(numThreads);
+ for (int i = 0; i < numThreads; i++) {
+ tasks.add(new Callable<Object>() {
+ @Override public Object call() throws Exception {
+ latch.countDown();
+ return lazy.get();
+ }
+ });
+ }
+
+ List<Future<Object>> futures = executor.invokeAll(tasks);
+
+ assert_().that(provider.provisions.get()).isEqualTo(1);
+ Set<Object> results = Sets.newIdentityHashSet();
+ for (Future<Object> future : futures) {
+ results.add(future.get());
+ }
+ assert_().that(results.size()).isEqualTo(1);
+ }
+
+ // TODO(gak): reenable this test once we can ensure that factories are no longer providing null
+ @Ignore @Test public void get_null() {
+ Lazy<Object> lazy = DoubleCheckLazy.create(new Provider<Object> () {
+ @Override public Object get() {
+ return null;
+ }
+ });
+ try {
+ lazy.get();
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ private static class LatchedProvider implements Provider<Object> {
+ final AtomicInteger provisions;
+ final CountDownLatch latch;
+
+ LatchedProvider(CountDownLatch latch) {
+ this.latch = latch;
+ this.provisions = new AtomicInteger();
+ }
+
+ @Override
+ public Object get() {
+ if (latch != null) {
+ Uninterruptibles.awaitUninterruptibly(latch);
+ }
+ provisions.incrementAndGet();
+ return new Object();
+ }
+ }
+}
diff --git a/core/src/test/java/dagger/internal/InstanceFactoryTest.java b/core/src/test/java/dagger/internal/InstanceFactoryTest.java
new file mode 100644
index 0000000..acaf20d
--- /dev/null
+++ b/core/src/test/java/dagger/internal/InstanceFactoryTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+public final class InstanceFactoryTest {
+ @Rule public final ExpectedException thrown = ExpectedException.none();
+
+ @Test public void instanceFactory() {
+ Object instance = new Object();
+ Factory<Object> factory = InstanceFactory.create(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ assert_().that(factory.get()).isEqualTo(instance);
+ }
+
+ @Test public void create_throwsNullPointerException() {
+ thrown.expect(NullPointerException.class);
+ InstanceFactory.create(null);
+ }
+}
diff --git a/core/src/test/java/dagger/internal/MapProviderFactoryTest.java b/core/src/test/java/dagger/internal/MapProviderFactoryTest.java
new file mode 100644
index 0000000..b4496e9
--- /dev/null
+++ b/core/src/test/java/dagger/internal/MapProviderFactoryTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+@SuppressWarnings("unchecked")
+public class MapProviderFactoryTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void nullKey() {
+ thrown.expect(NullPointerException.class);
+ MapProviderFactory.<String, Integer>builder(1).put(null, incrementingIntegerProvider(1));
+ }
+
+ @Test
+ public void nullValue() {
+ thrown.expect(NullPointerException.class);
+ MapProviderFactory.<String, Integer>builder(1).put("Hello", null);
+ }
+
+ @Test
+ public void iterationOrder() {
+ Provider<Integer> p1 = incrementingIntegerProvider(10);
+ Provider<Integer> p2 = incrementingIntegerProvider(20);
+ Provider<Integer> p3 = incrementingIntegerProvider(30);
+ Provider<Integer> p4 = incrementingIntegerProvider(40);
+ Provider<Integer> p5 = incrementingIntegerProvider(50);
+
+ Factory<Map<String, Provider<Integer>>> factory = MapProviderFactory
+ .<String, Integer>builder(4)
+ .put("two", p2)
+ .put("one", p1)
+ .put("three", p3)
+ .put("one", p5)
+ .put("four", p4)
+ .build();
+
+ Map<String, Provider<Integer>> expectedMap = new LinkedHashMap<String, Provider<Integer>>();
+ expectedMap.put("two", p2);
+ expectedMap.put("one", p1);
+ expectedMap.put("three", p3);
+ expectedMap.put("one", p5);
+ expectedMap.put("four", p4);
+ assert_()
+ .that(factory.get().entrySet())
+ .containsExactlyElementsIn(expectedMap.entrySet())
+ .inOrder();
+ }
+
+ private static Provider<Integer> incrementingIntegerProvider(int seed) {
+ final AtomicInteger value = new AtomicInteger(seed);
+ return new Provider<Integer>() {
+ @Override
+ public Integer get() {
+ return value.getAndIncrement();
+ }
+ };
+ }
+}
diff --git a/core/src/test/java/dagger/internal/ScopedProviderTest.java b/core/src/test/java/dagger/internal/ScopedProviderTest.java
new file mode 100644
index 0000000..84b02c5
--- /dev/null
+++ b/core/src/test/java/dagger/internal/ScopedProviderTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 javax.inject.Provider;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assert_;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link ScopedProvider}.
+ */
+@RunWith(JUnit4.class)
+public class ScopedProviderTest {
+ @Test public void create_nullPointerException() {
+ try {
+ ScopedProvider.create(null);
+ fail();
+ } catch (NullPointerException expected) { }
+ }
+
+ // TODO(gak): reenable this test once we can ensure that factories are no longer providing null
+ @Ignore @Test public void get_nullPointerException() {
+ Provider<Object> scopedProvider = ScopedProvider.create(new Factory<Object>() {
+ @Override public Object get() {
+ return null;
+ }
+ });
+ try {
+ scopedProvider.get();
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test public void get() {
+ Provider<Integer> scopedProvider = ScopedProvider.create(new Factory<Integer>() {
+ int i = 0;
+
+ @Override public Integer get() {
+ return i++;
+ }
+ });
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ assert_().that(scopedProvider.get()).isEqualTo(0);
+ }
+}
diff --git a/core/src/test/java/dagger/internal/SetFactoryTest.java b/core/src/test/java/dagger/internal/SetFactoryTest.java
new file mode 100644
index 0000000..04b9822
--- /dev/null
+++ b/core/src/test/java/dagger/internal/SetFactoryTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.google.common.collect.ContiguousSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Range;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.inject.Provider;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.collect.DiscreteDomain.integers;
+import static com.google.common.truth.Truth.assert_;
+
+@RunWith(JUnit4.class)
+@SuppressWarnings("unchecked")
+public class SetFactoryTest {
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void providerReturnsNullSet() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return null;
+ }
+ }, incrementingIntegerProvider(0));
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsNullSet_single() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return null;
+ }
+ });
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsSetWithNullElement() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
+ result.add(1);
+ result.add(null);
+ result.add(3);
+ return result;
+ }
+ });
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void providerReturnsSetWithNullElement_single() {
+ Factory<Set<Integer>> factory = SetFactory.create(new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ LinkedHashSet<Integer> result = new LinkedHashSet<Integer>();
+ result.add(1);
+ result.add(null);
+ result.add(3);
+ return result;
+ }
+ }, incrementingIntegerProvider(0));
+ thrown.expect(NullPointerException.class);
+ factory.get();
+ }
+
+ @Test
+ public void invokesProvidersEverytTime() {
+ Factory<Set<Integer>> factory = SetFactory.create(
+ incrementingIntegerProvider(0),
+ incrementingIntegerProvider(10),
+ incrementingIntegerProvider(20));
+ assert_().that(factory.get()).containsExactly(0, 10, 20);
+ assert_().that(factory.get()).containsExactly(1, 11, 21);
+ assert_().that(factory.get()).containsExactly(2, 12, 22);
+ }
+
+ @Test
+ public void iterationOrder() {
+ Factory<Set<Integer>> factory = SetFactory.create(
+ integerSetProvider(Range.closed(5, 9)),
+ integerSetProvider(Range.closed(3, 6)),
+ integerSetProvider(Range.closed(0, 5)));
+ assert_().that(factory.get()).containsExactly(5, 6, 7, 8, 9, 3, 4, 0, 1, 2).inOrder();
+ }
+
+ private static Provider<Set<Integer>> incrementingIntegerProvider(int seed) {
+ final AtomicInteger value = new AtomicInteger(seed);
+ return new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return ImmutableSet.of(value.getAndIncrement());
+ }
+ };
+ }
+
+ private static Provider<Set<Integer>> integerSetProvider(Range<Integer> range) {
+ final ContiguousSet<Integer> set = ContiguousSet.create(range, integers());
+ return new Provider<Set<Integer>>() {
+ @Override
+ public Set<Integer> get() {
+ return set;
+ }
+ };
+ }
+}
diff --git a/deploy_website.sh b/deploy_website.sh
new file mode 100755
index 0000000..1fde1bd
--- /dev/null
+++ b/deploy_website.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# Deploys the current Dagger website to the gh-pages branch of the GitHub
+# repository. To test the site locally before deploying run `jekyll --server`
+# in the website/ directory.
+
+set -ex
+
+REPO="git@github.com:square/dagger.git"
+GROUP_ID="com.squareup.dagger"
+ARTIFACT_ID="dagger"
+
+DIR=temp-dagger-clone
+
+# Delete any existing temporary website clone
+rm -rf $DIR
+
+# Clone the current repo into temp folder
+git clone $REPO $DIR
+
+# Move working directory into temp folder
+cd $DIR
+
+# Checkout and track the gh-pages branch
+git checkout -t origin/gh-pages
+
+# Delete everything
+rm -rf *
+
+# Copy website files from real repo
+cp -R ../website/* .
+
+# Download the latest javadoc
+curl -L "http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=$GROUP_ID&a=$ARTIFACT_ID&v=LATEST&c=javadoc" > javadoc.zip
+mkdir javadoc
+unzip javadoc.zip -d javadoc
+rm javadoc.zip
+
+# Stage all files in git and create a commit
+git add .
+git add -u
+git commit -m "Website at $(date)"
+
+# Push the new files up to GitHub
+git push origin gh-pages
+
+# Delete our temp folder
+cd ..
+rm -rf $DIR
diff --git a/examples/android-activity-graphs/README.md b/examples/android-activity-graphs/README.md
new file mode 100644
index 0000000..ac3680b
--- /dev/null
+++ b/examples/android-activity-graphs/README.md
@@ -0,0 +1,24 @@
+Example: Android Activity Graphs
+================================
+
+Building on top of the simple Android example, this example demonstrates how it is possible to
+create child graphs for each activity which extend from the global graph.
+
+Some of the advantages of the activity scope:
+
+ * Provides the ability to inject objects which require the activity to be constructed.
+ * Allows for the use of singletons on a per-activity basis. This is a great way to manage a
+ resource that is shared by a bunch of fragments in an activity.
+ * Keeps the global object graph clear of things that can be used only by activities.
+
+While this example only shows the presence of an activity scope, you should be able to see the
+potential for other useful scopes that can be used. For example, having a dedicated object graph
+for the current user session is a great way to manage data that is tied to the currently logged-in
+user.
+
+_Note: The app does not actually do anything when it is run. It is only to show how you can
+ structure Dagger within an Android app_
+
+_Note: The app is in transition to Dagger 2 and may not reflect recommended patterns. Before
+ we release Dagger 2.0 it will, but until this note is removed, please do not rely on this
+ example as a strong recommendation._
diff --git a/examples/android-activity-graphs/pom.xml b/examples/android-activity-graphs/pom.xml
new file mode 100644
index 0000000..340c59c
--- /dev/null
+++ b/examples/android-activity-graphs/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>android-activity-graphs</artifactId>
+ <name>Examples: Android - Activity Graphs</name>
+ <packaging>apk</packaging>
+
+ <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>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>support-v4</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.simpligility.maven.plugins</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/android-activity-graphs/src/main/AndroidManifest.xml b/examples/android-activity-graphs/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..234406d
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+ package="com.example.dagger.activitygraphs">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17"/>
+
+ <application
+ android:label="app_name"
+ android:name=".DemoApplication">
+ <activity
+ android:label="app_name"
+ android:name=".ui.HomeActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java
new file mode 100644
index 0000000..430838e
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/AbstractActivityComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import android.app.Activity;
+import dagger.Component;
+
+/**
+ * A base component upon which fragment's components may depend. Activity-level components
+ * should extend this component.
+ */
+@PerActivity // Subtypes of AbstractActivityComponent should be decorated with @PerActivity.
+@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
+public interface AbstractActivityComponent {
+ Activity activity(); // Expose the activity to sub-graphs.
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java
new file mode 100644
index 0000000..cf5462e
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ActivityModule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import android.app.Activity;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * A module to wrap the Activity state and expose it to the graph.
+ */
+@Module
+public class ActivityModule {
+ private final Activity activity;
+
+ public ActivityModule(Activity activity) {
+ this.activity = activity;
+ }
+
+ /**
+ * Expose the activity to dependents in the graph.
+ */
+ @Provides @PerActivity Activity activity() {
+ return activity;
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java
new file mode 100644
index 0000000..04c2062
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ApplicationComponent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import dagger.Component;
+import javax.inject.Singleton;
+
+/**
+ * A component whose lifetime is the life of the application.
+ */
+@Singleton // Constraints this component to one-per-application or unscoped bindings.
+@Component(modules = DemoApplicationModule.class)
+public interface ApplicationComponent {
+ // Field injections of any dependencies of the DemoApplication
+ void inject(DemoApplication application);
+
+ // Exported for child-components.
+ Application application();
+ LocationManager locationManager();
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java
new file mode 100644
index 0000000..7205733
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplication.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import javax.inject.Singleton;
+import javax.inject.Inject;
+
+public class DemoApplication extends Application {
+ private ApplicationComponent applicationComponent;
+
+ // TODO(cgruber): Figure out a better example of something one might inject into the app.
+ @Inject LocationManager locationManager; // to illustrate injecting something into the app.
+
+ @Override public void onCreate() {
+ super.onCreate();
+ applicationComponent = DaggerApplicationComponent.builder()
+ .demoApplicationModule(new DemoApplicationModule(this))
+ .build();
+ }
+
+ public ApplicationComponent component() {
+ return applicationComponent;
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java
new file mode 100644
index 0000000..070d2c7
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/DemoApplicationModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import android.app.Application;
+import android.location.LocationManager;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static android.content.Context.LOCATION_SERVICE;
+
+/**
+ * A module for Android-specific dependencies which require a {@link Context} or
+ * {@link android.app.Application} to create.
+ */
+@Module
+public class DemoApplicationModule {
+ private final Application application;
+
+ public DemoApplicationModule(Application application) {
+ this.application = application;
+ }
+
+ /**
+ * Expose the application to the graph.
+ */
+ @Provides @Singleton Application application() {
+ return application;
+ }
+
+ @Provides @Singleton LocationManager provideLocationManager() {
+ return (LocationManager) application.getSystemService(LOCATION_SERVICE);
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java
new file mode 100644
index 0000000..d54b193
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/PerActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * A scoping annotation to permit objects whose lifetime should
+ * conform to the life of the activity to be memoized in the
+ * correct component.
+ */
+@Scope
+@Retention(RUNTIME)
+public @interface PerActivity {
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java
new file mode 100644
index 0000000..c416c75
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/ActivityTitleController.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs.ui;
+
+import android.app.Activity;
+import com.example.dagger.activitygraphs.PerActivity;
+import javax.inject.Inject;
+
+/**
+ * A simple abstraction which provides the ability to set the title on an activity.
+ * <p>
+ * Fragments should not directly modify any part of an activity outside of the view or dialog that
+ * it creates. This class provides a way for fragments to inject a controller that will allow for
+ * control of the activity title. While not exceedingly useful in practice, this concept could be
+ * expanded to things like facilitating control over the action bar, dialogs, notifications, etc.
+ */
+@PerActivity
+public class ActivityTitleController {
+ private final Activity activity;
+
+ @Inject public ActivityTitleController(Activity activity) {
+ this.activity = activity;
+ }
+
+ public void setTitle(CharSequence title) {
+ activity.setTitle(title);
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java
new file mode 100644
index 0000000..1f3bb70
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeActivity.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs.ui;
+
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import com.example.dagger.activitygraphs.ActivityModule;
+import com.example.dagger.activitygraphs.DemoApplication;
+import javax.inject.Inject;
+
+public class HomeActivity extends FragmentActivity {
+ @Inject LocationManager locationManager;
+ private HomeComponent component;
+
+ HomeComponent component() {
+ if (component == null) {
+ component = DaggerHomeComponent.builder()
+ .applicationComponent(((DemoApplication) getApplication()).component())
+ .activityModule(new ActivityModule(this))
+ .build();
+ }
+ return component;
+ }
+
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ component().inject(this);
+
+ if (savedInstanceState == null) {
+ getSupportFragmentManager().beginTransaction()
+ .add(android.R.id.content, new HomeFragment())
+ .commit();
+ }
+
+ // TODO do something with the injected dependencies here!
+ }
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java
new file mode 100644
index 0000000..84d2a42
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeComponent.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs.ui;
+
+import com.example.dagger.activitygraphs.AbstractActivityComponent;
+import com.example.dagger.activitygraphs.ActivityModule;
+import com.example.dagger.activitygraphs.ApplicationComponent;
+import com.example.dagger.activitygraphs.PerActivity;
+import dagger.Component;
+
+@PerActivity
+@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
+public interface HomeComponent extends AbstractActivityComponent {
+ void inject(HomeActivity homeActivity);
+ void inject(HomeFragment homeFragment);
+}
diff --git a/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java
new file mode 100644
index 0000000..1df2724
--- /dev/null
+++ b/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs/ui/HomeFragment.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.activitygraphs.ui;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import javax.inject.Inject;
+
+import static android.view.Gravity.CENTER;
+
+public class HomeFragment extends Fragment {
+ @Inject ActivityTitleController titleController;
+
+ @Override public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ ((HomeActivity) getActivity()).component().inject(this);
+ }
+
+ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ TextView tv = new TextView(getActivity());
+ tv.setGravity(CENTER);
+ tv.setText("Hello, World");
+ return tv;
+ }
+
+ @Override public void onResume() {
+ super.onResume();
+
+ // Fragments should not modify things outside of their own view. Use an external controller to
+ // ask the activity to change its title.
+ titleController.setTitle("Home Fragment");
+ }
+}
diff --git a/examples/android-simple/README.md b/examples/android-simple/README.md
new file mode 100644
index 0000000..944d015
--- /dev/null
+++ b/examples/android-simple/README.md
@@ -0,0 +1,17 @@
+Example: Android Simple
+=======================
+
+This example demonstrates how to structure an Android application with Dagger.
+
+A custom `Application` class is used to manage a global object graph of objects. Modules are
+assembled with a `getModules` method on the application that can be overridden to add additional
+modules in development versions of your applications or in tests.
+
+Injection of activities is done automatically in a base activity.
+
+_Note: The app does not actually do anything when it is run. It is only to show how you can
+ structure Dagger within an Android app_
+
+_Note: The app is in transition to Dagger 2 and may not reflect recommended patterns. Before
+ we release Dagger 2.0 it will, but until this note is removed, please do not rely on this
+ example as a strong recommendation._
diff --git a/examples/android-simple/pom.xml b/examples/android-simple/pom.xml
new file mode 100644
index 0000000..fb934e6
--- /dev/null
+++ b/examples/android-simple/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>android-simple</artifactId>
+ <name>Examples: Android - Simple</name>
+ <packaging>apk</packaging>
+
+ <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>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.simpligility.maven.plugins</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/android-simple/src/main/AndroidManifest.xml b/examples/android-simple/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..53c83bf
--- /dev/null
+++ b/examples/android-simple/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0.0"
+ package="com.example.dagger.simple">
+
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17"/>
+
+ <application
+ android:label="app_name"
+ android:name=".DemoApplication">
+ <activity
+ android:label="app_name"
+ android:name=".ui.HomeActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java b/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java
new file mode 100644
index 0000000..18184d1
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/AndroidModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.simple;
+
+import android.content.Context;
+import android.location.LocationManager;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+import static android.content.Context.LOCATION_SERVICE;
+
+/**
+ * A module for Android-specific dependencies which require a {@link Context} or
+ * {@link android.app.Application} to create.
+ */
+@Module
+public class AndroidModule {
+ private final DemoApplication application;
+
+ public AndroidModule(DemoApplication application) {
+ this.application = application;
+ }
+
+ /**
+ * Allow the application context to be injected but require that it be annotated with
+ * {@link ForApplication @Annotation} to explicitly differentiate it from an activity context.
+ */
+ @Provides @Singleton @ForApplication Context provideApplicationContext() {
+ return application;
+ }
+
+ @Provides @Singleton LocationManager provideLocationManager() {
+ return (LocationManager) application.getSystemService(LOCATION_SERVICE);
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java
new file mode 100644
index 0000000..aa09f2d
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.simple;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public abstract class DemoActivity extends Activity {
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Perform injection so that when this call returns all dependencies will be available for use.
+ ((DemoApplication) getApplication()).component().inject(this);
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java
new file mode 100644
index 0000000..55402c6
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/DemoApplication.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.simple;
+
+import android.app.Application;
+import android.location.LocationManager;
+import com.example.dagger.simple.ui.HomeActivity;
+import dagger.Component;
+import java.util.Arrays;
+import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+public class DemoApplication extends Application {
+
+ @Singleton
+ @Component(modules = AndroidModule.class)
+ public interface ApplicationComponent {
+ void inject(DemoApplication application);
+ void inject(HomeActivity homeActivity);
+ void inject(DemoActivity demoActivity);
+ }
+
+ @Inject LocationManager locationManager; // for some reason.
+
+ private ApplicationComponent component;
+
+ @Override public void onCreate() {
+ super.onCreate();
+ component = DaggerDemoApplication_ApplicationComponent.builder()
+ .androidModule(new AndroidModule(this))
+ .build();
+ component().inject(this); // As of now, LocationManager should be injected into this.
+ }
+
+ public ApplicationComponent component() {
+ return component;
+ }
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java b/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java
new file mode 100644
index 0000000..84d2247
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/ForApplication.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.simple;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Qualifier @Retention(RUNTIME)
+public @interface ForApplication {
+}
diff --git a/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java b/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java
new file mode 100644
index 0000000..7e33b8e
--- /dev/null
+++ b/examples/android-simple/src/main/java/com/example/dagger/simple/ui/HomeActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.dagger.simple.ui;
+
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import com.example.dagger.simple.DemoActivity;
+import com.example.dagger.simple.DemoApplication;
+import javax.inject.Inject;
+
+public class HomeActivity extends DemoActivity {
+ @Inject LocationManager locationManager;
+
+ @Override protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ((DemoApplication) getApplication()).component().inject(this);
+
+ // TODO do something with the injected dependencies here!
+ Log.d("HomeActivity", locationManager.toString());
+ }
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index c12050d..eb4685a 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2013 The Dagger Authors.
+ Copyright (C) 2013 Google, Inc.
+ Copyright (C) 2013 Square, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,38 +19,34 @@
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.sonatype.oss</groupId>
- <artifactId>oss-parent</artifactId>
- <version>9</version>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</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>
+ <module>android-simple</module>
+ <module>android-activity-graphs</module>
</modules>
<!-- Example-only dependencies. -->
<dependencyManagement>
<dependencies>
<dependency>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger</artifactId>
- <version>${project.version}</version>
+ <groupId>com.google.android</groupId>
+ <artifactId>android</artifactId>
+ <version>4.1.1.4</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>
+ <groupId>com.google.android</groupId>
+ <artifactId>support-v4</artifactId>
+ <version>r7</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -64,6 +61,17 @@
<target>1.6</target>
</configuration>
</plugin>
+ <plugin>
+ <groupId>com.simpligility.maven.plugins</groupId>
+ <artifactId>android-maven-plugin</artifactId>
+ <version>4.3.0</version>
+ <configuration>
+ <sdk>
+ <platform>23</platform>
+ <path>${env.ANDROID_HOME}</path>
+ </sdk>
+ </configuration>
+ </plugin>
</plugins>
</pluginManagement>
</build>
diff --git a/examples/simple/pom.xml b/examples/simple/pom.xml
index ffc99dc..0be10b8 100644
--- a/examples/simple/pom.xml
+++ b/examples/simple/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2012 The Dagger Authors.
+ Copyright (C) 2012 Square, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
<parent>
<groupId>com.google.dagger.example</groupId>
<artifactId>dagger-example-parent</artifactId>
- <version>2.17</version>
+ <version>2.1-SNAPSHOT</version>
</parent>
<artifactId>simple</artifactId>
@@ -28,32 +28,15 @@
<dependencies>
<dependency>
- <!-- Force the correct version of Guava to be on the classpath. -->
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
- <artifactId>dagger</artifactId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ <optional>true</optional>
</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
index 7a2b9a6..b0a93ec 100644
--- a/examples/simple/src/main/java/coffee/CoffeeApp.java
+++ b/examples/simple/src/main/java/coffee/CoffeeApp.java
@@ -6,12 +6,12 @@
public class CoffeeApp {
@Singleton
@Component(modules = { DripCoffeeModule.class })
- public interface CoffeeShop {
+ public interface Coffee {
CoffeeMaker maker();
}
public static void main(String[] args) {
- CoffeeShop coffeeShop = DaggerCoffeeApp_CoffeeShop.builder().build();
- coffeeShop.maker().brew();
+ Coffee coffee = DaggerCoffeeApp_Coffee.builder().build();
+ coffee.maker().brew();
}
}
diff --git a/examples/simple/src/main/java/coffee/PumpModule.java b/examples/simple/src/main/java/coffee/PumpModule.java
index df00b86..338ad33 100644
--- a/examples/simple/src/main/java/coffee/PumpModule.java
+++ b/examples/simple/src/main/java/coffee/PumpModule.java
@@ -1,10 +1,11 @@
package coffee;
-import dagger.Binds;
import dagger.Module;
+import dagger.Provides;
@Module
-abstract class PumpModule {
- @Binds
- abstract Pump providePump(Thermosiphon pump);
+class PumpModule {
+ @Provides Pump providePump(Thermosiphon pump) {
+ return pump;
+ }
}
diff --git a/gwt/BUILD b/gwt/BUILD
deleted file mode 100644
index da73013..0000000
--- a/gwt/BUILD
+++ /dev/null
@@ -1,50 +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:
-# GWT-specific files for Dagger
-
-package(default_visibility = ["//:src"])
-
-load("//tools:maven.bzl", "pom_file", "POM_VERSION")
-
-java_library(
- name = "gwt",
- resource_strip_prefix = "gwt/",
- resources = glob(["**/*.gwt.xml"]),
- tags = ["maven_coordinates=com.google.dagger:dagger-gwt:" + POM_VERSION],
- exports = [
- ":manual_deps",
- "//java/dagger:core",
- ],
-)
-
-java_library(
- name = "manual_deps",
- tags = [
- "maven_coordinates=com.google.dagger:dagger:%s:jar:sources" % POM_VERSION,
- "maven_coordinates=javax.inject:javax.inject:1:jar:sources",
- ],
- visibility = ["//visibility:private"],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-gwt",
- artifact_name = "Dagger GWT",
- targets = [
- ":gwt",
- ":manual_deps",
- ],
-)
diff --git a/gwt/dagger/Dagger.gwt.xml b/gwt/dagger/Dagger.gwt.xml
deleted file mode 100644
index ad106fd..0000000
--- a/gwt/dagger/Dagger.gwt.xml
+++ /dev/null
@@ -1,20 +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.
--->
-<module>
- <inherits name="javax.inject.Inject" />
-
- <source path=""/>
-</module>
diff --git a/gwt/javax/inject/Inject.gwt.xml b/gwt/javax/inject/Inject.gwt.xml
deleted file mode 100644
index b634926..0000000
--- a/gwt/javax/inject/Inject.gwt.xml
+++ /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.
--->
-<module>
- <source path=""/>
-</module>
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
deleted file mode 100644
index 57941b3..0000000
--- a/jarjar-rules.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# shade guava to avoid conflicts with guava embedded in Error Prone.
-rule com.google.common.** com.google.dagger.common.@1
-rule com.google.auto.** com.google.dagger.auto.@1
diff --git a/java/dagger/BUILD b/java/dagger/BUILD
deleted file mode 100644
index 3485431..0000000
--- a/java/dagger/BUILD
+++ /dev/null
@@ -1,58 +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 JSR-330 compliant dependency injection system for android and java
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "SOURCE_7_TARGET_7",
-)
-load("//tools:maven.bzl", "POM_VERSION", "pom_file")
-
-java_library(
- name = "core",
- srcs = glob(["**/*.java"]),
- javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX,
- tags = ["maven_coordinates=com.google.dagger:dagger:" + POM_VERSION],
- exports = ["@google_bazel_common//third_party/java/jsr330_inject"],
- deps = [
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger",
- artifact_name = "Dagger",
- targets = [":core"],
-)
-
-filegroup(
- name = "javadoc-srcs",
- srcs = glob(["**/*"]),
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "core-javadoc",
- srcs = [":javadoc-srcs"],
- exclude_packages = ["dagger.internal"],
- root_packages = ["dagger"],
- deps = ["@google_bazel_common//third_party/java/jsr330_inject"],
-)
diff --git a/java/dagger/Binds.java b/java/dagger/Binds.java
deleted file mode 100644
index 99b65e2..0000000
--- a/java/dagger/Binds.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;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates <em>abstract</em> methods of a {@link Module} that delegate bindings. For example, to
- * bind {@link java.util.Random} to {@link java.security.SecureRandom} a module could declare the
- * following: {@code @Binds abstract Random bindRandom(SecureRandom secureRandom);}
- *
- * <p>{@code @Binds} methods are a drop-in replacement for {@link Provides} methods that simply
- * return an injected parameter. Prefer {@code @Binds} because the generated implementation is
- * likely to be more efficient.
- *
- * <p>A {@code @Binds} method:
- *
- * <ul>
- * <li>Must be {@code abstract}.
- * <li>May be {@linkplain javax.inject.Scope scoped}.
- * <li>May be {@linkplain javax.inject.Qualifier qualified}.
- * <li>Must have a single parameter whose type is assignable to the return type. The return type
- * declares the bound type (just as it would for a {@literal @}{@link dagger.Provides} method)
- * and the parameter is the type to which it is bound.
- * <p>For {@linkplain dagger.multibindings multibindings}, assignability is checked in similar
- * ways:
- * <dl>
- * <dt>{@link dagger.multibindings.IntoSet}
- * <dd>The parameter must be assignable to the only parameter of {@link java.util.Set#add}
- * when viewed as a member of the return type — the parameter must be assignable to the
- * return type.
- * <dt>{@link dagger.multibindings.ElementsIntoSet}
- * <dd>The parameter must be assignable to the only parameter of {@link
- * java.util.Set#addAll} when viewed as a member of the return type — if the return type
- * is {@code Set<E>}, the parameter must be assignable to {@code Collection<? extends
- * E>}.
- * <dt>{@link dagger.multibindings.IntoMap}
- * <dd>The parameter must be assignable to the {@code value} parameter of {@link
- * java.util.Map#put} when viewed as a member of a {@link java.util.Map} in which {@code
- * V} is bound to the return type — the parameter must be assignable to the return type
- * </dl>
- * </ul>
- */
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface Binds {}
diff --git a/java/dagger/BindsInstance.java b/java/dagger/BindsInstance.java
deleted file mode 100644
index eab8796..0000000
--- a/java/dagger/BindsInstance.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;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Marks a method on a {@linkplain Component.Builder component builder} or a parameter on a
- * {@linkplain Component.Factory component factory} as binding an instance to some key within the
- * component.
- *
- * <p>For example:
- *
- * <pre>
- * {@literal @Component.Builder}
- * interface Builder {
- * {@literal @BindsInstance} Builder foo(Foo foo);
- * {@literal @BindsInstance} Builder bar({@literal @Blue} Bar bar);
- * ...
- * }
- *
- * // or
- *
- * {@literal @Component.Factory}
- * interface Factory {
- * MyComponent newMyComponent(
- * {@literal @BindsInstance} Foo foo,
- * {@literal @BindsInstance @Blue} Bar bar);
- * }
- * </pre>
- *
- * <p>will allow clients of the builder or factory to pass their own instances of {@code Foo} and
- * {@code Bar}, and those instances can be injected within the component as {@code Foo} or
- * {@code @Blue Bar}, respectively.
- *
- * <p>{@code @BindsInstance} arguments may not be {@code null} unless the parameter is annotated
- * with {@code @Nullable}.
- *
- * <p>For builders, {@code @BindsInstance} methods must be called before building the component,
- * unless their parameter is marked {@code @Nullable}, in which case the component will act as
- * though it was called with a {@code null} argument. Primitives, of course, may not be marked
- * {@code @Nullable}.
- *
- * <p>Binding an instance is equivalent to passing an instance to a module constructor and providing
- * that instance, but is often more efficient. When possible, binding object instances should be
- * preferred to using module instances.
- */
-@Documented
-@Retention(RUNTIME)
-@Target({METHOD, PARAMETER})
-@Beta
-public @interface BindsInstance {}
diff --git a/java/dagger/BindsOptionalOf.java b/java/dagger/BindsOptionalOf.java
deleted file mode 100644
index 9a356ff..0000000
--- a/java/dagger/BindsOptionalOf.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;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-
-/**
- * Annotates methods that declare bindings for {@code Optional} containers of values from bindings
- * that may or may not be present in the component.
- *
- * <p>If a module contains a method declaration like this:
- *
- * <pre>
- * {@literal @BindsOptionalOf} abstract Foo optionalFoo();</pre>
- *
- * then any binding in the component can depend on an {@code Optional} of {@code Foo}. If there is
- * no binding for {@code Foo} in the component, the {@code Optional} will be absent. If there is a
- * binding for {@code Foo} in the component, the {@code Optional} will be present, and its value
- * will be the value given by the binding for {@code Foo}.
- *
- * <p>A {@code @BindsOptionalOf} method:
- *
- * <ul>
- * <li>must be {@code abstract}
- * <li>may have a {@linkplain Qualifier qualifier} annotation
- * <li>must not return {@code void}
- * <li>must not have parameters
- * <li>must not throw exceptions
- * <li>must not return an unqualified type with an {@link Inject @Inject}-annotated constructor,
- * since such a type is always present
- * </ul>
- *
- * <p>Other bindings may inject any of:
- *
- * <ul>
- * <li>{@code Optional<Foo>} (unless there is a {@code @Nullable} binding for {@code Foo}; see
- * below)
- * <li>{@code Optional<Provider<Foo>>}
- * <li>{@code Optional<Lazy<Foo>>}
- * <li>{@code Optional<Provider<Lazy<Foo>>>}
- * </ul>
- *
- * <p>If there is a binding for {@code Foo}, and that binding is {@code @Nullable}, then it is a
- * compile-time error to inject {@code Optional<Foo>}, because {@code Optional} cannot contain
- * {@code null}. You can always inject the other forms, because {@link Provider} and {@link Lazy}
- * can always return {@code null} from their {@code get()} methods.
- *
- * <p>Explicit bindings for any of the above will conflict with a {@code @BindsOptionalOf} binding.
- *
- * <p>If the binding for {@code Foo} is a {@code @Produces} binding, then another {@code @Produces}
- * binding can depend on any of:
- *
- * <ul>
- * <li>{@code Optional<Foo>}
- * <!-- TODO(dpb): Update this once producers support nullability checks -->
- * <li>{@code Optional<Producer<Foo>>}
- * <li>{@code Optional<Produced<Foo>>}
- * </ul>
- *
- * <p>You can inject either {@code com.google.common.base.Optional} or {@code java.util.Optional}.
- */
-@Documented
-@Beta
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface BindsOptionalOf {}
diff --git a/java/dagger/Component.java b/java/dagger/Component.java
deleted file mode 100644
index 709b0e6..0000000
--- a/java/dagger/Component.java
+++ /dev/null
@@ -1,365 +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;
-
-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;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-import javax.inject.Scope;
-import javax.inject.Singleton;
-
-/**
- * Annotates an interface or abstract class for which a fully-formed, dependency-injected
- * implementation is to be generated from a set of {@linkplain #modules}. The generated class will
- * have the name of the type annotated with {@code @Component} prepended with {@code Dagger}. For
- * example, {@code @Component interface MyComponent {...}} will produce an implementation named
- * {@code DaggerMyComponent}.
- *
- * <a name="component-methods"></a>
- * <h2>Component methods</h2>
- *
- * <p>Every type annotated with {@code @Component} must contain at least one abstract component
- * method. Component methods may have any name, but must have signatures that conform to either
- * {@linkplain Provider provision} or {@linkplain MembersInjector members-injection} contracts.
- *
- * <a name="provision-methods"></a>
- * <h3>Provision methods</h3>
- *
- * <p>Provision methods have no parameters and return an {@link Inject injected} or {@link Provides
- * provided} type. Each method may have a {@link Qualifier} annotation as well. The following are
- * all valid provision method declarations:
- *
- * <pre><code>
- * SomeType getSomeType();
- * {@literal Set<SomeType>} getSomeTypes();
- * {@literal @PortNumber} int getPortNumber();
- * </code></pre>
- *
- * <p>Provision methods, like typical {@link Inject injection} sites, may use {@link Provider} or
- * {@link Lazy} to more explicitly control provision requests. A {@link Provider} allows the user of
- * the component to request provision any number of times by calling {@link Provider#get}. A {@link
- * Lazy} will only ever request a single provision, but will defer it until the first call to {@link
- * Lazy#get}. The following provision methods all request provision of the same type, but each
- * implies different semantics:
- *
- * <pre><code>
- * SomeType getSomeType();
- * {@literal Provider<SomeType>} getSomeTypeProvider();
- * {@literal Lazy<SomeType>} getLazySomeType();
- * </code></pre>
- *
- * <a name="members-injection-methods"></a>
- * <h3>Members-injection methods</h3>
- *
- * <p>Members-injection methods have a single parameter and inject dependencies into each of the
- * {@link Inject}-annotated fields and methods of the passed instance. A members-injection method
- * may be void or return its single parameter as a convenience for chaining. The following are all
- * valid members-injection method declarations:
- *
- * <pre><code>
- * void injectSomeType(SomeType someType);
- * SomeType injectAndReturnSomeType(SomeType someType);
- * </code></pre>
- *
- * <p>A method with no parameters that returns a {@link MembersInjector} is equivalent to a members
- * injection method. Calling {@link MembersInjector#injectMembers} on the returned object will
- * perform the same work as a members injection method. For example:
- *
- * <pre><code>
- * {@literal MembersInjector<SomeType>} getSomeTypeMembersInjector();
- * </code></pre>
- *
- * <h4>A note about covariance</h4>
- *
- * <p>While a members-injection method for a type will accept instances of its subtypes, only {@link
- * Inject}-annotated members of the parameter type and its supertypes will be injected; members of
- * subtypes will not. For example, given the following types, only {@code a} and {@code b} will be
- * injected into an instance of {@code Child} when it is passed to the members-injection method
- * {@code injectSelf(Self instance)}:
- *
- * <pre><code>
- * class Parent {
- * {@literal @}Inject A a;
- * }
- *
- * class Self extends Parent {
- * {@literal @}Inject B b;
- * }
- *
- * class Child extends Self {
- * {@literal @}Inject C c;
- * }
- * </code></pre>
- *
- * <a name="instantiation"></a>
- * <h2>Instantiation</h2>
- *
- * <p>Component implementations are primarily instantiated via a generated <a
- * href="http://en.wikipedia.org/wiki/Builder_pattern">builder</a> or <a
- * href="https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)">factory</a>.
- *
- * <p>If a nested {@link Builder @Component.Builder} or {@link Factory @Component.Factory} type
- * exists in the component, Dagger will generate an implementation of that type. If neither exists,
- * Dagger will generate a builder type that has a method to set each of the {@linkplain #modules}
- * and component {@linkplain #dependencies} named with the <a
- * href="http://en.wikipedia.org/wiki/CamelCase">lower camel case</a> version of the module or
- * dependency type.
- *
- * <p>In either case, the Dagger-generated component type will have a static method, named either
- * {@code builder()} or {@code factory()}, that returns a builder or factory instance.
- *
- * <p>Example of using a builder:
- *
- * <pre>{@code
- * public static void main(String[] args) {
- * OtherComponent otherComponent = ...;
- * MyComponent component = DaggerMyComponent.builder()
- * // required because component dependencies must be set
- * .otherComponent(otherComponent)
- * // required because FlagsModule has constructor parameters
- * .flagsModule(new FlagsModule(args))
- * // may be elided because a no-args constructor is visible
- * .myApplicationModule(new MyApplicationModule())
- * .build();
- * }
- * }</pre>
- *
- * <p>Example of using a factory:
- *
- * <pre>{@code
- * public static void main(String[] args) {
- * OtherComponent otherComponent = ...;
- * MyComponent component = DaggerMyComponent.factory()
- * .create(otherComponent, new FlagsModule(args), new MyApplicationModule());
- * // Note that all parameters to a factory method are required, even if one is for a module
- * // that Dagger could instantiate. The only case where null is legal is for a
- * // @BindsInstance @Nullable parameter.
- * }
- * }</pre>
- *
- * <p>In the case that a component has no component dependencies and only no-arg modules, the
- * generated component will also have a factory method {@code create()}. {@code
- * SomeComponent.create()} and {@code SomeComponent.builder().build()} are both valid and
- * equivalent.
- *
- * <a name="scope"></a>
- * <h2>Scope</h2>
- *
- * <p>Each Dagger component can be associated with a scope by annotating it with the {@linkplain
- * Scope scope annotation}. The component implementation ensures that there is only one provision of
- * each scoped binding per instance of the component. If the component declares a scope, it may only
- * contain unscoped bindings or bindings of that scope anywhere in the graph. For example:
- *
- * <pre><code>
- * {@literal @}Singleton {@literal @}Component
- * interface MyApplicationComponent {
- * // this component can only inject types using unscoped or {@literal @}Singleton bindings
- * }
- * </code></pre>
- *
- * <p>In order to get the proper behavior associated with a scope annotation, it is the caller's
- * responsibility to instantiate new component instances when appropriate. A {@link Singleton}
- * component, for instance, should only be instantiated once per application, while a {@code
- * RequestScoped} component should be instantiated once per request. Because components are
- * self-contained implementations, exiting a scope is as simple as dropping all references to the
- * component instance.
- *
- * <a name="component-relationships"></a>
- * <h2>Component relationships</h2>
- *
- * <p>While there is much utility in isolated components with purely unscoped bindings, many
- * applications will call for multiple components with multiple scopes to interact. Dagger provides
- * two mechanisms for relating components.
- *
- * <a name="subcomponents"></a>
- * <h3>Subcomponents</h3>
- *
- * <p>The simplest way to relate two components is by declaring a {@link Subcomponent}. A
- * subcomponent behaves exactly like a component, but has its implementation generated within a
- * parent component or subcomponent. That relationship allows the subcomponent implementation to
- * inherit the <em>entire</em> binding graph from its parent when it is declared. For that reason, a
- * subcomponent isn't evaluated for completeness until it is associated with a parent.
- *
- * <p>Subcomponents are declared by listing the class in the {@link Module#subcomponents()}
- * attribute of one of the parent component's modules. This binds the {@link Subcomponent.Builder}
- * or {@link Subcomponent.Factory} for that subcomponent within the parent component.
- *
- * <p>Subcomponents may also be declared via a factory method on a parent component or subcomponent.
- * The method may have any name, but must return the subcomponent. The factory method's parameters
- * may be any number of the subcomponent's modules, but must at least include those without visible
- * no-arg constructors. The following is an example of a factory method that creates a
- * request-scoped subcomponent from a singleton-scoped parent:
- *
- * <pre><code>
- * {@literal @}Singleton {@literal @}Component
- * interface ApplicationComponent {
- * // component methods...
- *
- * RequestComponent newRequestComponent(RequestModule requestModule);
- * }
- * </code></pre>
- *
- * <a name="component-dependencies"></a>
- * <h3>Component dependencies</h3>
- *
- * <p>While subcomponents are the simplest way to compose subgraphs of bindings, subcomponents are
- * tightly coupled with the parents; they may use any binding defined by their ancestor component
- * and subcomponents. As an alternative, components can use bindings only from another <em>component
- * interface</em> by declaring a {@linkplain #dependencies component dependency}. When a type is
- * used as a component dependency, each <a href="#provision-methods">provision method</a> on the
- * dependency is bound as a provider. Note that <em>only</em> the bindings exposed as provision
- * methods are available through component dependencies.
- *
- * @since 2.0
- */
-@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
-@Target(TYPE)
-@Documented
-public @interface Component {
- /**
- * A list of classes annotated with {@link Module} whose bindings are used to generate the
- * component implementation. Note that through the use of {@link Module#includes} the full set of
- * modules used to implement the component may include more modules that just those listed here.
- */
- Class<?>[] modules() default {};
-
- /**
- * A list of types that are to be used as <a href="#component-dependencies">component
- * dependencies</a>.
- */
- Class<?>[] dependencies() default {};
-
- /**
- * A builder for a component.
- *
- * <p>A builder is a type with setter methods for the {@linkplain Component#modules modules},
- * {@linkplain Component#dependencies dependencies} and {@linkplain BindsInstance bound instances}
- * required by the component and a single no-argument build method that creates a new component
- * instance.
- *
- * <p>Components may have a single nested {@code static abstract class} or {@code interface}
- * annotated with {@code @Component.Builder}. If they do, then Dagger will generate a builder
- * class that implements that type. Note that a component with a {@code @Component.Builder} may
- * not also have a {@code @Component.Factory}.
- *
- * <p>Builder types must follow some rules:
- *
- * <ul>
- * <li>There <i>must</i> be exactly one abstract no-argument method that returns the component
- * type or one of its supertypes, called the "build method".
- * <li>There <i>may</i> be other other abstract methods, called "setter methods".
- * <li>Setter methods <i>must</i> take a single argument and return {@code void}, the builder
- * type or a supertype of the builder type.
- * <li>There <i>must</i> be a setter method for each {@linkplain Component#dependencies
- * component dependency}.
- * <li>There <i>must</i> be a setter method for each non-{@code abstract} {@linkplain
- * Component#modules module} that has non-{@code static} binding methods, unless Dagger can
- * instantiate that module with a visible no-argument constructor.
- * <li>There <i>may</i> be setter methods for modules that Dagger can instantiate or does not
- * need to instantiate.
- * <li>There <i>may</i> be setter methods annotated with {@code @BindsInstance}. These methods
- * bind the instance passed to them within the component. See {@link
- * BindsInstance @BindsInstance} for more information.
- * <li>There <i>may</i> be non-{@code abstract} methods, but they are ignored as far as
- * validation and builder generation are concerned.
- * </ul>
- *
- * For example, this could be a valid {@code Component} with a {@code Builder}:
- *
- * <pre><code>
- * {@literal @}Component(modules = {BackendModule.class, FrontendModule.class})
- * interface MyComponent {
- * MyWidget myWidget();
- *
- * {@literal @}Component.Builder
- * interface Builder {
- * Builder backendModule(BackendModule bm);
- * Builder frontendModule(FrontendModule fm);
- * {@literal @}BindsInstance
- * Builder foo(Foo foo);
- * MyComponent build();
- * }
- * }</code></pre>
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Builder {}
-
- /**
- * A factory for a component.
- *
- * <p>A factory is a type with a single method that returns a new component instance each time it
- * is called. The parameters of that method allow the caller to provide the {@linkplain
- * Component#modules modules}, {@linkplain Component#dependencies dependencies} and {@linkplain
- * BindsInstance bound instances} required by the component.
- *
- * <p>Components may have a single nested {@code static abstract class} or {@code interface}
- * annotated with {@code @Component.Factory}. If they do, then Dagger will generate a factory
- * class that will implement that type. Note that a component with a {@code @Component.Factory}
- * may not also have a {@code @Component.Builder}.
- *
- * <p>Factory types must follow some rules:
- *
- * <ul>
- * <li>There <i>must</i> be exactly one abstract method, which must return the component type or
- * one of its supertypes.
- * <li>The method <i>must</i> have a parameter for each {@linkplain Component#dependencies
- * component dependency}.
- * <li>The method <i>must</i> have a parameter for each non-{@code abstract} {@linkplain
- * Component#modules module} that has non-{@code static} binding methods, unless Dagger can
- * instantiate that module with a visible no-argument constructor.
- * <li>The method <i>may</i> have parameters for modules that Dagger can instantiate or does not
- * need to instantiate.
- * <li>The method <i>may</i> have parameters annotated with {@code @BindsInstance}. These
- * parameters bind the instance passed for that parameter within the component. See {@link
- * BindsInstance @BindsInstance} for more information.
- * <li>There <i>may</i> be non-{@code abstract} methods, but they are ignored as far as
- * validation and factory generation are concerned.
- * </ul>
- *
- * For example, this could be a valid {@code Component} with a {@code Factory}:
- *
- * <pre><code>
- * {@literal @}Component(modules = {BackendModule.class, FrontendModule.class})
- * interface MyComponent {
- * MyWidget myWidget();
- *
- * {@literal @}Component.Factory
- * interface Factory {
- * MyComponent newMyComponent(
- * BackendModule bm, FrontendModule fm, {@literal @}BindsInstance Foo foo);
- * }
- * }</code></pre>
- *
- * <p>For a root component, if a {@code @Component.Factory} is defined, the generated component
- * type will have a {@code static} method named {@code factory()} that returns an instance of that
- * factory.
- *
- * @since 2.22
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Factory {}
-}
diff --git a/java/dagger/Lazy.java b/java/dagger/Lazy.java
deleted file mode 100644
index d4408fa..0000000
--- a/java/dagger/Lazy.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.
- */
-
-package dagger;
-
-/**
- * A handle to a lazily-computed value. Each {@code Lazy} computes its value on
- * the first call to {@link #get()} and remembers that same value for all
- * subsequent calls to {@code get()}.
- *
- * <p>All implementations are expected to be thread-safe and compute their value at most once.
- *
- * <h2>Example</h2>
- * The differences between <strong>direct injection</strong>, <strong>provider
- * injection</strong> and <strong>lazy injection</strong> are best demonstrated
- * with an example. Start with a module that computes a different integer for
- * each use:<pre><code>
- * {@literal @Module}
- * final class CounterModule {
- * int next = 100;
- *
- * {@literal @Provides} Integer provideInteger() {
- * System.out.println("computing...");
- * return next++;
- * }
- * }
- * </code></pre>
- *
- * <h3>Direct Injection</h3>
- * This class injects that integer and prints it 3 times:<pre><code>
- * final class DirectCounter {
- * {@literal @Inject} Integer value;
- *
- * void print() {
- * System.out.println("printing...");
- * System.out.println(value);
- * System.out.println(value);
- * System.out.println(value);
- * }
- * }
- * </code></pre>
- * Injecting a {@code DirectCounter} and invoking {@code print()} reveals that
- * the value is computed <i>before</i> it is required:<pre><code>
- * computing...
- * printing...
- * 100
- * 100
- * 100
- * </code></pre>
- *
- * <h3>Provider Injection</h3>
- * This class injects a {@linkplain javax.inject.Provider provider} for the
- * integer. It calls {@code Provider.get()} 3 times and prints each result:
- * <pre><code>
- * final class ProviderCounter {
- * {@literal @Inject Provider<Integer> provider;}
- *
- * void print() {
- * System.out.println("printing...");
- * System.out.println(provider.get());
- * System.out.println(provider.get());
- * System.out.println(provider.get());
- * }
- * }
- * </code></pre>
- * Injecting a {@code ProviderCounter} and invoking {@code print()} shows that
- * a new value is computed each time {@code Provider.get()} is used:<pre><code>
- * printing...
- * computing...
- * 100
- * computing...
- * 101
- * computing...
- * 102
- * </code></pre>
- *
- * <h3>Lazy Injection</h3>
- * This class injects a {@code Lazy} for the integer. Like the provider above,
- * it calls {@code Lazy.get()} 3 times and prints each result:<pre><code>
- * final class LazyCounter {
- * {@literal @Inject Lazy<Integer> lazy;}
- *
- * void print() {
- * System.out.println("printing...");
- * System.out.println(lazy.get());
- * System.out.println(lazy.get());
- * System.out.println(lazy.get());
- * }
- * }
- * </code></pre>
- * Injecting a {@code LazyCounter} and invoking {@code print()} shows that a new
- * value is computed immediately before it is needed. The same value is returned
- * for all subsequent uses:<pre><code>
- * printing...
- * computing...
- * 100
- * 100
- * 100
- * </code></pre>
- *
- * <h3>Lazy != Singleton</h3>
- * Note that each injected {@code Lazy} is independent, and remembers its value
- * in isolation of other {@code Lazy} instances. In this example, two {@code
- * LazyCounter} objects are created and {@code print()} is called on each:
- * <pre><code>
- * final class LazyCounters {
- * {@literal @Inject} LazyCounter counter1;
- * {@literal @Inject} LazyCounter counter2;
- *
- * void print() {
- * counter1.print();
- * counter2.print();
- * }
- * }
- * </code></pre>
- * The output demonstrates that each {@code Lazy} works independently:
- * <pre><code>
- * printing...
- * computing...
- * 100
- * 100
- * 100
- * printing...
- * computing...
- * 101
- * 101
- * 101
- * </code></pre>
- * Use {@link javax.inject.Singleton @Singleton} to share one instance among all
- * clients, and {@code Lazy} for lazy computation in a single client.
- */
-public interface Lazy<T> {
- /**
- * Return the underlying value, computing the value if necessary. All calls to
- * the same {@code Lazy} instance will return the same result.
- */
- T get();
-}
diff --git a/java/dagger/MapKey.java b/java/dagger/MapKey.java
deleted file mode 100644
index 46dbf93..0000000
--- a/java/dagger/MapKey.java
+++ /dev/null
@@ -1,116 +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;
-
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.util.Map;
-
-/**
- * Identifies annotation types that are used to associate keys with values returned by {@linkplain
- * Provides provider methods} in order to compose a {@linkplain dagger.multibindings.IntoMap map}.
- *
- * <p>Every provider method annotated with {@code @Provides} and {@code @IntoMap} must also have an
- * annotation that identifies the key for that map entry. That annotation's type must be annotated
- * with {@code @MapKey}.
- *
- * <p>Typically, the key annotation has a single member, whose value is used as the map key.
- *
- * <p>For example, to add an entry to a {@code Map<SomeEnum, Integer>} with key {@code
- * SomeEnum.FOO}, you could use an annotation called {@code @SomeEnumKey}:
- *
- * <pre><code>
- * {@literal @}MapKey
- * {@literal @}interface SomeEnumKey {
- * SomeEnum value();
- * }
- *
- * {@literal @}Module
- * class SomeModule {
- * {@literal @}Provides
- * {@literal @}IntoMap
- * {@literal @}SomeEnumKey(SomeEnum.FOO)
- * Integer provideFooValue() {
- * return 2;
- * }
- * }
- *
- * class SomeInjectedType {
- * {@literal @}Inject
- * SomeInjectedType({@literal Map<SomeEnum, Integer>} map) {
- * assert map.get(SomeEnum.FOO) == 2;
- * }
- * }
- * </code></pre>
- *
- * <p>If {@code unwrapValue} is true, the annotation's single member can be any type except an
- * array.
- *
- * <p>See {@link dagger.multibindings} for standard unwrapped map key annotations for keys that are
- * boxed primitives, strings, or classes.
- *
- * <h2>Annotations as keys</h2>
- *
- * <p>If {@link #unwrapValue} is false, then the annotation itself is used as the map key. For
- * example, to add an entry to a {@code Map<MyMapKey, Integer>} map:
- *
- * <pre><code>
- * {@literal @}MapKey(unwrapValue = false)
- * {@literal @}interface MyMapKey {
- * String someString();
- * MyEnum someEnum();
- * }
- *
- * {@literal @}Module
- * class SomeModule {
- * {@literal @}Provides
- * {@literal @}IntoMap
- * {@literal @}MyMapKey(someString = "foo", someEnum = BAR)
- * Integer provideFooBarValue() {
- * return 2;
- * }
- * }
- *
- * class SomeInjectedType {
- * {@literal @}Inject
- * SomeInjectedType({@literal Map<MyMapKey, Integer>} map) {
- * assert map.get(new MyMapKeyImpl("foo", MyEnum.BAR)) == 2;
- * }
- * }
- * </code></pre>
- *
- * <p>(Note that there must be a class {@code MyMapKeyImpl} that implements {@code MyMapKey} in
- * order to call {@link Map#get(Object)} on the provided map.)
- *
- * @see <a href="https://dagger.dev/multibindings#map-multibindings">Map multibinding</a>
- */
-@Documented
-@Target(ANNOTATION_TYPE)
-@Retention(RUNTIME)
-public @interface MapKey {
- /**
- * True to use the value of the single member of the annotated annotation as the map key; false
- * to use the annotation instance as the map key.
- *
- * <p>If true, the single member must not be an array.
- */
- boolean unwrapValue() default true;
-}
diff --git a/java/dagger/MembersInjector.java b/java/dagger/MembersInjector.java
deleted file mode 100644
index 5e83889..0000000
--- a/java/dagger/MembersInjector.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-
-package dagger;
-
-/**
- * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
- * presence or absence of an injectable constructor.
- *
- * @param <T> type to inject members of
- *
- * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept
- * {@code null})
- */
-public interface MembersInjector<T> {
-
- /**
- * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
- * absence of an injectable constructor.
- *
- * <p>Whenever a {@link Component} creates an instance, it performs this injection automatically
- * (after first performing constructor injection), so if you're able to let the component create
- * all your objects for you, you'll never need to use this method.
- *
- * @param instance into which members are to be injected
- * @throws NullPointerException if {@code instance} is {@code null}
- */
- void injectMembers(T instance);
-}
diff --git a/java/dagger/Module.java b/java/dagger/Module.java
deleted file mode 100644
index bd32a1f..0000000
--- a/java/dagger/Module.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-package dagger;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a class that contributes to the object graph.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface Module {
- /**
- * Additional {@code @Module}-annotated classes from which this module is
- * composed. The de-duplicated contributions of the modules in
- * {@code includes}, and of their inclusions recursively, are all contributed
- * to the object graph.
- */
- Class<?>[] includes() default {};
-
- /**
- * Any {@link Subcomponent}- or {@code @ProductionSubcomponent}-annotated classes which should be
- * children of the component in which this module is installed. A subcomponent may be listed in
- * more than one module in a component.
- *
- * @since 2.7
- */
- @Beta
- Class<?>[] subcomponents() default {};
-}
diff --git a/java/dagger/Provides.java b/java/dagger/Provides.java
deleted file mode 100644
index a60be3b..0000000
--- a/java/dagger/Provides.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2007 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates methods of a {@linkplain Module module} to create a provider method binding. The
- * method's return type is bound to its returned value. The {@linkplain Component component}
- * implementation will pass dependencies to the method as parameters.
- *
- * <h3>Nullability</h3>
- *
- * <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 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
- * attempts to pair a {@code @Nullable} provision with a non-{@code @Nullable} injection site
- * will fail to compile.
- */
-@Documented @Target(METHOD) @Retention(RUNTIME)
-public @interface Provides {
-}
diff --git a/java/dagger/Reusable.java b/java/dagger/Reusable.java
deleted file mode 100644
index 2cb68aa..0000000
--- a/java/dagger/Reusable.java
+++ /dev/null
@@ -1,38 +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;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * A scope that indicates that the object returned by a binding may be (but might not be) reused.
- *
- * <p>{@code @Reusable} is useful when you want to limit the number of provisions of a type, but
- * there is no specific lifetime over which there must be only one instance.
- *
- * @see <a href="https://dagger.dev/users-guide#reusable-scope">Reusable Scope</a>
- */
-@Documented
-@Beta
-@Retention(RUNTIME)
-@Scope
-public @interface Reusable {}
diff --git a/java/dagger/Subcomponent.java b/java/dagger/Subcomponent.java
deleted file mode 100644
index 2bf087f..0000000
--- a/java/dagger/Subcomponent.java
+++ /dev/null
@@ -1,76 +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;
-
-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;
-
-/**
- * A subcomponent that inherits the bindings from a parent {@link Component} or
- * {@link Subcomponent}. The details of how to associate a subcomponent with a parent are described
- * in the documentation for {@link Component}.
- *
- * @since 2.0
- */
-@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
-@Target(TYPE)
-@Documented
-public @interface Subcomponent {
- /**
- * A list of classes annotated with {@link Module} whose bindings are used to generate the
- * subcomponent implementation. Note that through the use of {@link Module#includes} the full set
- * of modules used to implement the subcomponent may include more modules that just those listed
- * here.
- */
- Class<?>[] modules() default {};
-
- /**
- * A builder for a subcomponent.
- *
- * <p>This follows all the rules of {@link Component.Builder}, except it must appear in classes
- * annotated with {@link Subcomponent} instead of {@code Component}.
- *
- * <p>If a subcomponent defines a builder, its parent component(s) will have a binding for that
- * builder type, allowing an instance or {@code Provider} of that builder to be injected or
- * returned from a method on that component like any other binding.
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Builder {}
-
- /**
- * A factory for a subcomponent.
- *
- * <p>This follows all the rules of {@link Component.Factory}, except it must appear in classes
- * annotated with {@link Subcomponent} instead of {@code Component}.
- *
- * <p>If a subcomponent defines a factory, its parent component(s) will have a binding for that
- * factory type, allowing an instance of that factory to be injected or returned from a method on
- * that component like any other binding.
- *
- * @since 2.22
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Factory {}
-}
diff --git a/java/dagger/android/AndroidInjection.java b/java/dagger/android/AndroidInjection.java
deleted file mode 100644
index 2f4fb4c..0000000
--- a/java/dagger/android/AndroidInjection.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.android;
-
-import static android.util.Log.DEBUG;
-import static dagger.internal.Preconditions.checkNotNull;
-
-import android.app.Activity;
-import android.app.Application;
-import android.app.Fragment;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.ContentProvider;
-import android.content.Context;
-import android.util.Log;
-import dagger.internal.Beta;
-
-/** Injects core Android types. */
-@Beta
-public final class AndroidInjection {
- private static final String TAG = "dagger.android";
-
- /**
- * Injects {@code activity} if an associated {@link AndroidInjector} implementation can be found,
- * otherwise throws an {@link IllegalArgumentException}.
- *
- * @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector} or {@link HasActivityInjector}.
- */
- public static void inject(Activity activity) {
- checkNotNull(activity, "activity");
- Application application = activity.getApplication();
- 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 or %s",
- application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName(),
- HasActivityInjector.class.getCanonicalName()));
- }
-
- 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 {@link AndroidInjector} to use to
- * inject {@code fragment}:
- *
- * <ol>
- * <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} 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} or {@link HasFragmentInjector}, a {@link
- * IllegalArgumentException} is thrown.
- *
- * @throws IllegalArgumentException if no parent fragment, activity, or application implements
- * {@link HasAndroidInjector} or {@link HasFragmentInjector}.
- */
- public static void inject(Fragment fragment) {
- checkNotNull(fragment, "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(),
- hasInjector.getClass().getCanonicalName()));
- }
-
- injector.inject(fragment);
- }
-
- private static Object findHasFragmentInjector(Fragment fragment) {
- Fragment parentFragment = fragment;
- while ((parentFragment = parentFragment.getParentFragment()) != null) {
- if (parentFragment instanceof HasAndroidInjector
- || parentFragment instanceof HasFragmentInjector) {
- return parentFragment;
- }
- }
- Activity activity = fragment.getActivity();
- if (activity instanceof HasAndroidInjector || activity instanceof HasFragmentInjector) {
- return activity;
- }
- 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()));
- }
-
- /**
- * Injects {@code service} if an associated {@link AndroidInjector} implementation can be found,
- * otherwise throws an {@link IllegalArgumentException}.
- *
- * @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector} or {@link HasServiceInjector}.
- */
- public static void inject(Service service) {
- checkNotNull(service, "service");
- Application application = service.getApplication();
- 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 or %s",
- application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName(),
- HasServiceInjector.class.getCanonicalName()));
- }
-
- injector.inject(service);
- }
-
- /**
- * Injects {@code broadcastReceiver} if an associated {@link AndroidInjector} implementation can
- * be found, otherwise throws an {@link IllegalArgumentException}.
- *
- * @throws RuntimeException if the {@link Application} from {@link
- * 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();
- 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 or %s",
- application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName(),
- HasBroadcastReceiverInjector.class.getCanonicalName()));
- }
-
- injector.inject(broadcastReceiver);
- }
-
- /**
- * Injects {@code contentProvider} if an associated {@link AndroidInjector} implementation can be
- * found, otherwise throws an {@link IllegalArgumentException}.
- *
- * @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector} or {@link HasContentProviderInjector}.
- */
- public static void inject(ContentProvider contentProvider) {
- checkNotNull(contentProvider, "contentProvider");
- Application application = (Application) contentProvider.getContext().getApplicationContext();
-
- 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 or %s",
- application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName(),
- HasBroadcastReceiverInjector.class.getCanonicalName()));
- }
-
- injector.inject(contentProvider);
- }
-
- private AndroidInjection() {}
-}
diff --git a/java/dagger/android/AndroidInjectionKey.java b/java/dagger/android/AndroidInjectionKey.java
deleted file mode 100644
index d4a5d72..0000000
--- a/java/dagger/android/AndroidInjectionKey.java
+++ /dev/null
@@ -1,44 +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.android;
-
-import static java.lang.annotation.ElementType.METHOD;
-
-import dagger.MapKey;
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Target;
-
-/**
- * {@link MapKey} annotation to key {@link AndroidInjector.Factory} bindings. The {@linkplain
- * #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/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
-@Target(METHOD)
-@Documented
-public @interface AndroidInjectionKey {
- /** The fully qualified class name of the type to be injected. */
- String value();
-}
diff --git a/java/dagger/android/AndroidInjectionModule.java b/java/dagger/android/AndroidInjectionModule.java
deleted file mode 100644
index 4e496f8..0000000
--- a/java/dagger/android/AndroidInjectionModule.java
+++ /dev/null
@@ -1,39 +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.android;
-
-import dagger.Module;
-import dagger.internal.Beta;
-import dagger.multibindings.Multibinds;
-import java.util.Map;
-
-/**
- * Contains bindings to ensure the usability of {@code dagger.android} framework classes. This
- * module should be installed in the component that is used to inject the {@link
- * android.app.Application} class.
- */
-@Beta
-@Module
-public abstract class AndroidInjectionModule {
- @Multibinds
- abstract Map<Class<?>, AndroidInjector.Factory<?>> classKeyedInjectorFactories();
-
- @Multibinds
- abstract Map<String, AndroidInjector.Factory<?>> stringKeyedInjectorFactories();
-
- private AndroidInjectionModule() {}
-}
diff --git a/java/dagger/android/AndroidInjector.java b/java/dagger/android/AndroidInjector.java
deleted file mode 100644
index d2b9dec..0000000
--- a/java/dagger/android/AndroidInjector.java
+++ /dev/null
@@ -1,83 +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.android;
-
-import dagger.BindsInstance;
-import dagger.internal.Beta;
-
-/**
- * Performs members-injection for a concrete subtype of a <a
- * href="https://developer.android.com/guide/components/">core Android type</a> (e.g., {@link
- * android.app.Activity} or {@link android.app.Fragment}).
- *
- * <p>Commonly implemented by {@link dagger.Subcomponent}-annotated types whose {@link
- * dagger.Subcomponent.Factory} extends {@link Factory}.
- *
- * @param <T> a concrete subtype of a core Android type
- * @see AndroidInjection
- * @see DispatchingAndroidInjector
- * @see ContributesAndroidInjector
- */
-@Beta
-public interface AndroidInjector<T> {
-
- /** Injects the members of {@code instance}. */
- void inject(T instance);
-
- /**
- * Creates {@link AndroidInjector}s for a concrete subtype of a core Android type.
- *
- * @param <T> the concrete type to be injected
- */
- interface Factory<T> {
- /**
- * Creates an {@link AndroidInjector} for {@code instance}. This should be the same instance
- * that will be passed to {@link #inject(Object)}.
- */
- AndroidInjector<T> create(@BindsInstance T instance);
- }
-
- /**
- * An adapter that lets the common {@link dagger.Subcomponent.Builder} pattern implement {@link
- * Factory}.
- *
- * @param <T> the concrete type to be injected
- * @deprecated Prefer {@link Factory} now that components can have {@link dagger.Component.Factory
- * factories} instead of builders
- */
- @Deprecated
- abstract class Builder<T> implements AndroidInjector.Factory<T> {
- @Override
- public final AndroidInjector<T> create(T instance) {
- seedInstance(instance);
- return build();
- }
-
- /**
- * Provides {@code instance} to be used in the binding graph of the built {@link
- * AndroidInjector}. By default, this is used as a {@link BindsInstance} method, but it may be
- * overridden to provide any modules which need a reference to the activity.
- *
- * <p>This should be the same instance that will be passed to {@link #inject(Object)}.
- */
- @BindsInstance
- public abstract void seedInstance(T instance);
-
- /** Returns a newly-constructed {@link AndroidInjector}. */
- public abstract AndroidInjector<T> build();
- }
-}
diff --git a/java/dagger/android/AndroidManifest.xml b/java/dagger/android/AndroidManifest.xml
deleted file mode 100644
index f071b60..0000000
--- a/java/dagger/android/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.android">
- <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD
deleted file mode 100644
index a88d16e..0000000
--- a/java/dagger/android/BUILD
+++ /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.
-
-# Description:
-# Public Dagger API for Android
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
- "SOURCE_7_TARGET_7",
-)
-load("//tools:maven.bzl", "POM_VERSION", "pom_file")
-
-# Work around b/70476182 which prevents Kythe from connecting :producers to the .java files it
-# contains.
-SRCS = glob([
- "*.java",
- "internal/*.java",
-])
-
-filegroup(
- name = "android-srcs",
- srcs = SRCS,
-)
-
-android_library(
- name = "android",
- srcs = SRCS,
- javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- manifest = "AndroidManifest.xml",
- proguard_specs = ["proguard.cfg"],
- tags = ["maven_coordinates=com.google.dagger:dagger-android:" + POM_VERSION],
- deps = [
- ":manual-maven-deps",
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- ],
-)
-
-# 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",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-android",
- artifact_name = "Dagger Android",
- packaging = "aar",
- targets = [":android"],
-)
-
-# b/37741866 and https://github.com/google/dagger/issues/715
-pom_file(
- name = "jarimpl-pom",
- artifact_id = "dagger-android-jarimpl",
- artifact_name = "Dagger Android",
- targets = [":android"],
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "android-javadoc",
- srcs = [":android-srcs"],
- android_api_level = 26,
- exclude_packages = ["dagger.android.internal"],
- root_packages = ["dagger.android"],
- deps = [":android"],
-)
diff --git a/java/dagger/android/ContributesAndroidInjector.java b/java/dagger/android/ContributesAndroidInjector.java
deleted file mode 100644
index 5aa9312..0000000
--- a/java/dagger/android/ContributesAndroidInjector.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.android;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Generates an {@link AndroidInjector} for the return type of this method. The injector is
- * implemented with a {@link dagger.Subcomponent} and will be a child of the {@link dagger.Module}'s
- * component.
- *
- * <p>This annotation must be applied to an abstract method in a {@link dagger.Module} that returns
- * a concrete Android framework type (e.g. {@code FooActivity}, {@code BarFragment}, {@code
- * MyService}, etc). The method should have no parameters.
- *
- * <p>For more information, see <a href="https://dagger.dev/android">the docs</a>
- */
-@Documented
-@Retention(RUNTIME)
-@Target(METHOD)
-public @interface ContributesAndroidInjector {
- /** Modules to be installed in the generated {@link dagger.Subcomponent}. */
- Class<?>[] modules() default {};
-}
diff --git a/java/dagger/android/DaggerActivity.java b/java/dagger/android/DaggerActivity.java
deleted file mode 100644
index 43708f3..0000000
--- a/java/dagger/android/DaggerActivity.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.android;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * An {@link Activity} that injects its members in {@link #onCreate(Bundle)} and can be used to
- * inject {@link Fragment}s attached to it.
- */
-@Beta
-public abstract class DaggerActivity extends Activity implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- AndroidInjection.inject(this);
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/DaggerApplication.java b/java/dagger/android/DaggerApplication.java
deleted file mode 100644
index d09050b..0000000
--- a/java/dagger/android/DaggerApplication.java
+++ /dev/null
@@ -1,82 +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.android;
-
-import android.app.Application;
-import android.content.ContentProvider;
-import com.google.errorprone.annotations.ForOverride;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * An {@link Application} that injects its members and can be used to inject objects that the
- * Android framework instantiates, such as Activitys, Fragments, or Services. Injection is performed
- * in {@link #onCreate()} or the first call to {@link AndroidInjection#inject(ContentProvider)},
- * whichever happens first.
- */
-@Beta
-public abstract class DaggerApplication extends Application implements HasAndroidInjector {
- @Inject volatile DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onCreate() {
- super.onCreate();
- injectIfNecessary();
- }
-
- /**
- * Implementations should return an {@link AndroidInjector} for the concrete {@link
- * DaggerApplication}. Typically, that injector is a {@link dagger.Component}.
- */
- @ForOverride
- protected abstract AndroidInjector<? extends DaggerApplication> applicationInjector();
-
- /**
- * Lazily injects the {@link DaggerApplication}'s members. Injection cannot be performed in {@link
- * Application#onCreate()} since {@link android.content.ContentProvider}s' {@link
- * android.content.ContentProvider#onCreate() onCreate()} method will be called first and might
- * need injected members on the application. Injection is not performed in the constructor, as
- * that may result in members-injection methods being called before the constructor has completed,
- * allowing for a partially-constructed instance to escape.
- */
- private void injectIfNecessary() {
- if (androidInjector == null) {
- synchronized (this) {
- if (androidInjector == null) {
- @SuppressWarnings("unchecked")
- AndroidInjector<DaggerApplication> applicationInjector =
- (AndroidInjector<DaggerApplication>) applicationInjector();
- applicationInjector.inject(this);
- if (androidInjector == null) {
- throw new IllegalStateException(
- "The AndroidInjector returned from applicationInjector() did not inject the "
- + "DaggerApplication");
- }
- }
- }
- }
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- // injectIfNecessary should already be called unless we are about to inject a ContentProvider,
- // which can happen before Application.onCreate()
- injectIfNecessary();
-
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/DaggerBroadcastReceiver.java b/java/dagger/android/DaggerBroadcastReceiver.java
deleted file mode 100644
index d39aa86..0000000
--- a/java/dagger/android/DaggerBroadcastReceiver.java
+++ /dev/null
@@ -1,49 +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.android;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.support.annotation.CallSuper;
-import dagger.internal.Beta;
-
-/**
- * A {@link BroadcastReceiver} that injects its members in every call to {@link #onReceive(Context,
- * Intent)}.
- *
- * <p>This class should only be used for {@link BroadcastReceiver}s that are declared in an {@code
- * AndroidManifest.xml}. If, instead, the {@link BroadcastReceiver} is created in code, prefer
- * constructor injection.
- *
- * <p>Note: this class is <em>not thread safe</em> and should not be used with multiple {@link
- * android.os.Handler}s in calls to {@link Context#registerReceiver(BroadcastReceiver,
- * android.content.IntentFilter, String, android.os.Handler)}. Injection is performed on each
- * invocation to {@link #onReceive(Context, Intent)} which could result in inconsistent views of
- * injected dependencies across threads.
- *
- * <p>Subclasses should override {@link #onReceive(Context, Intent)} and call {@code
- * super.onReceive(context, intent)} immediately to ensure injection is performed immediately.
- */
-@Beta
-public abstract class DaggerBroadcastReceiver extends BroadcastReceiver {
- @CallSuper
- @Override
- public void onReceive(Context context, Intent intent) {
- AndroidInjection.inject(this, context);
- }
-}
diff --git a/java/dagger/android/DaggerContentProvider.java b/java/dagger/android/DaggerContentProvider.java
deleted file mode 100644
index 4aad485..0000000
--- a/java/dagger/android/DaggerContentProvider.java
+++ /dev/null
@@ -1,32 +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.android;
-
-import android.content.ContentProvider;
-import android.support.annotation.CallSuper;
-import dagger.internal.Beta;
-
-/** A {@link ContentProvider} that injects its members in {@link #onCreate()}. */
-@Beta
-public abstract class DaggerContentProvider extends ContentProvider {
- @CallSuper
- @Override
- public boolean onCreate() {
- AndroidInjection.inject(this);
- return true;
- }
-}
diff --git a/java/dagger/android/DaggerDialogFragment.java b/java/dagger/android/DaggerDialogFragment.java
deleted file mode 100644
index 3cbc0f1..0000000
--- a/java/dagger/android/DaggerDialogFragment.java
+++ /dev/null
@@ -1,50 +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.android;
-
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.content.Context;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * A {@link DialogFragment} that injects its members in {@link #onAttach(Context)} and can be used
- * to inject child {@link Fragment}s attached to it. Note that when this fragment gets reattached,
- * its members will be injected again.
- *
- * @deprecated Framework fragments are deprecated in Android P; prefer {@code
- * dagger.android.support.DaggerDialogFragment} to use a support-library-friendly {@code
- * dagger.android} dialog fragment implementation.
- */
-@Deprecated
-@Beta
-public abstract class DaggerDialogFragment extends DialogFragment implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onAttach(Context context) {
- AndroidInjection.inject(this);
- super.onAttach(context);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/DaggerFragment.java b/java/dagger/android/DaggerFragment.java
deleted file mode 100644
index 187820b..0000000
--- a/java/dagger/android/DaggerFragment.java
+++ /dev/null
@@ -1,49 +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.android;
-
-import android.app.Fragment;
-import android.content.Context;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * A {@link Fragment} that injects its members in {@link #onAttach(Context)} and can be used to
- * inject child {@link Fragment}s attached to it. Note that when this fragment gets reattached, its
- * members will be injected again.
- *
- * @deprecated Framework fragments are deprecated in Android P; prefer {@code
- * dagger.android.support.DaggerFragment} to use a support-library-friendly {@code
- * dagger.android} fragment implementation.
- */
-@Beta
-@Deprecated
-public abstract class DaggerFragment extends Fragment implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onAttach(Context context) {
- AndroidInjection.inject(this);
- super.onAttach(context);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/DaggerIntentService.java b/java/dagger/android/DaggerIntentService.java
deleted file mode 100644
index 7d9dabb..0000000
--- a/java/dagger/android/DaggerIntentService.java
+++ /dev/null
@@ -1,34 +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.android;
-
-import android.app.IntentService;
-import dagger.internal.Beta;
-
-/** An {@link IntentService} that injects its members in {@link #onCreate()}. */
-@Beta
-public abstract class DaggerIntentService extends IntentService {
- public DaggerIntentService(String name) {
- super(name);
- }
-
- @Override
- public void onCreate() {
- AndroidInjection.inject(this);
- super.onCreate();
- }
-}
diff --git a/java/dagger/android/DaggerService.java b/java/dagger/android/DaggerService.java
deleted file mode 100644
index cfc6d6b..0000000
--- a/java/dagger/android/DaggerService.java
+++ /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.
- */
-
-package dagger.android;
-
-import android.app.Service;
-import dagger.internal.Beta;
-
-/** A {@link Service} that injects its members in {@link #onCreate()}. */
-@Beta
-public abstract class DaggerService extends Service {
- @Override
- public void onCreate() {
- AndroidInjection.inject(this);
- super.onCreate();
- }
-}
diff --git a/java/dagger/android/DispatchingAndroidInjector.java b/java/dagger/android/DispatchingAndroidInjector.java
deleted file mode 100644
index 9b65180..0000000
--- a/java/dagger/android/DispatchingAndroidInjector.java
+++ /dev/null
@@ -1,166 +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.android;
-
-import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-import static dagger.internal.Preconditions.checkNotNull;
-
-import android.app.Activity;
-import android.app.Fragment;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.Beta;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Performs members-injection on instances of core Android types (e.g. {@link Activity}, {@link
- * Fragment}) that are constructed by the Android framework and not by Dagger. This class relies on
- * an injected mapping from each concrete class to an {@link AndroidInjector.Factory} for an {@link
- * AndroidInjector} of that class. Each concrete class must have its own entry in the map, even if
- * it extends another class which is already present in the map. Calls {@link Object#getClass()} on
- * the instance in order to find the appropriate {@link AndroidInjector.Factory}.
- *
- * @param <T> the core Android type to be injected
- */
-@Beta
-public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
- private static final String NO_SUPERTYPES_BOUND_FORMAT =
- "No injector factory bound for Class<%s>";
- private static final String SUPERTYPES_BOUND_FORMAT =
- "No injector factory bound for Class<%1$s>. Injector factories were bound for supertypes "
- + "of %1$s: %2$s. Did you mean to bind an injector factory for the subtype?";
-
- private final Map<String, Provider<AndroidInjector.Factory<?>>> injectorFactories;
-
- @Inject
- DispatchingAndroidInjector(
- Map<Class<?>, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithClassKeys,
- Map<String, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithStringKeys) {
- this.injectorFactories = merge(injectorFactoriesWithClassKeys, injectorFactoriesWithStringKeys);
- }
-
- /**
- * Merges the two maps into one by transforming the values of the {@code classKeyedMap} with
- * {@link Class#getName()}.
- *
- * <p>An SPI plugin verifies the logical uniqueness of the keysets of these two maps so we're
- * assured there's no overlap.
- *
- * <p>Ideally we could achieve this with a generic {@code @Provides} method, but we'd need to have
- * <i>N</i> modules that each extend one base module.
- */
- private static <C, V> Map<String, Provider<AndroidInjector.Factory<?>>> merge(
- Map<Class<? extends C>, V> classKeyedMap, Map<String, V> stringKeyedMap) {
- if (classKeyedMap.isEmpty()) {
- @SuppressWarnings({"unchecked", "rawtypes"})
- Map<String, Provider<AndroidInjector.Factory<?>>> safeCast = (Map) stringKeyedMap;
- return safeCast;
- }
-
- Map<String, V> merged =
- newLinkedHashMapWithExpectedSize(classKeyedMap.size() + stringKeyedMap.size());
- merged.putAll(stringKeyedMap);
- for (Entry<Class<? extends C>, V> entry : classKeyedMap.entrySet()) {
- merged.put(entry.getKey().getName(), entry.getValue());
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- Map<String, Provider<AndroidInjector.Factory<?>>> safeCast = (Map) merged;
- return Collections.unmodifiableMap(safeCast);
- }
-
- /**
- * Attempts to perform members-injection on {@code instance}, returning {@code true} if
- * successful, {@code false} otherwise.
- *
- * @throws InvalidInjectorBindingException if the injector factory bound for a class does not
- * inject instances of that class
- */
- @CanIgnoreReturnValue
- public boolean maybeInject(T instance) {
- Provider<AndroidInjector.Factory<?>> factoryProvider =
- injectorFactories.get(instance.getClass().getName());
- if (factoryProvider == null) {
- return false;
- }
-
- @SuppressWarnings("unchecked")
- AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
- try {
- AndroidInjector<T> injector =
- checkNotNull(
- factory.create(instance), "%s.create(I) should not return null.", factory.getClass());
-
- injector.inject(instance);
- return true;
- } catch (ClassCastException e) {
- throw new InvalidInjectorBindingException(
- String.format(
- "%s does not implement AndroidInjector.Factory<%s>",
- factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
- e);
- }
- }
-
- /**
- * Performs members-injection on {@code instance}.
- *
- * @throws InvalidInjectorBindingException if the injector factory bound for a class does not
- * inject instances of that class
- * @throws IllegalArgumentException if no {@link AndroidInjector.Factory} is bound for {@code
- * instance}
- */
- @Override
- public void inject(T instance) {
- boolean wasInjected = maybeInject(instance);
- if (!wasInjected) {
- throw new IllegalArgumentException(errorMessageSuggestions(instance));
- }
- }
-
- /**
- * Exception thrown if an incorrect binding is made for a {@link AndroidInjector.Factory}. If you
- * see this exception, make sure the value in your {@code @ActivityKey(YourActivity.class)} or
- * {@code @FragmentKey(YourFragment.class)} matches the type argument of the injector factory.
- */
- @Beta
- public static final class InvalidInjectorBindingException extends RuntimeException {
- InvalidInjectorBindingException(String message, ClassCastException cause) {
- super(message, cause);
- }
- }
-
- /** Returns an error message with the class names that are supertypes of {@code instance}. */
- private String errorMessageSuggestions(T instance) {
- List<String> suggestions = new ArrayList<>();
- for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
- if (injectorFactories.containsKey(clazz.getCanonicalName())) {
- suggestions.add(clazz.getCanonicalName());
- }
- }
-
- return suggestions.isEmpty()
- ? String.format(NO_SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName())
- : String.format(
- SUPERTYPES_BOUND_FORMAT, instance.getClass().getCanonicalName(), suggestions);
- }
-}
diff --git a/java/dagger/android/HasActivityInjector.java b/java/dagger/android/HasActivityInjector.java
deleted file mode 100644
index 136bbad..0000000
--- a/java/dagger/android/HasActivityInjector.java
+++ /dev/null
@@ -1,28 +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.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/HasAndroidInjector.java b/java/dagger/android/HasAndroidInjector.java
deleted file mode 100644
index 3b49718..0000000
--- a/java/dagger/android/HasAndroidInjector.java
+++ /dev/null
@@ -1,26 +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.android;
-
-import dagger.internal.Beta;
-
-/** Provides an {@link AndroidInjector}. */
-@Beta
-public interface HasAndroidInjector {
- /** Returns an {@link AndroidInjector}. */
- AndroidInjector<Object> androidInjector();
-}
diff --git a/java/dagger/android/HasBroadcastReceiverInjector.java b/java/dagger/android/HasBroadcastReceiverInjector.java
deleted file mode 100644
index b2aa992..0000000
--- a/java/dagger/android/HasBroadcastReceiverInjector.java
+++ /dev/null
@@ -1,28 +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.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
deleted file mode 100644
index 997ddb8..0000000
--- a/java/dagger/android/HasContentProviderInjector.java
+++ /dev/null
@@ -1,28 +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.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
deleted file mode 100644
index 564f32d..0000000
--- a/java/dagger/android/HasFragmentInjector.java
+++ /dev/null
@@ -1,28 +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.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
deleted file mode 100644
index d1c6a6c..0000000
--- a/java/dagger/android/HasServiceInjector.java
+++ /dev/null
@@ -1,28 +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.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
deleted file mode 100644
index f30b92c..0000000
--- a/java/dagger/android/internal/AndroidInjectionKeys.java
+++ /dev/null
@@ -1,37 +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.android.internal;
-
-/**
- * An internal implementation detail of Dagger's generated code. This is not guaranteed to remain
- * consistent from version to version.
- */
-public final class AndroidInjectionKeys {
- /**
- * Accepts the fully qualified name of a class that is injected with {@code dagger.android}.
- *
- * <p>From a runtime perspective, this method does nothing except return its single argument. It
- * is used as a signal to bytecode shrinking tools that its argument should be rewritten if it
- * corresponds to a class that has been obfuscated/relocated. Once it is done so, it is expected
- * that the argument will be inlined and this method will go away.
- */
- public static String of(String mapKey) {
- return mapKey;
- }
-
- private AndroidInjectionKeys() {}
-}
diff --git a/java/dagger/android/package-info.java b/java/dagger/android/package-info.java
deleted file mode 100644
index f59ef48..0000000
--- a/java/dagger/android/package-info.java
+++ /dev/null
@@ -1,21 +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.
- */
-
-/** APIs to assist with performing injection on Android. */
-@CheckReturnValue
-package dagger.android;
-
-import com.google.errorprone.annotations.CheckReturnValue;
diff --git a/java/dagger/android/processor/AndroidInjectorDescriptor.java b/java/dagger/android/processor/AndroidInjectorDescriptor.java
deleted file mode 100644
index 3ec6613..0000000
--- a/java/dagger/android/processor/AndroidInjectorDescriptor.java
+++ /dev/null
@@ -1,187 +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.android.processor;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-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 java.util.stream.Collectors.toList;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeName;
-import dagger.Module;
-import dagger.android.ContributesAndroidInjector;
-import java.util.List;
-import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.inject.Qualifier;
-import javax.inject.Scope;
-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.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-import javax.tools.Diagnostic.Kind;
-
-/**
- * A descriptor of a generated {@link Module} and {@link dagger.Subcomponent} to be generated from a
- * {@link ContributesAndroidInjector} method.
- */
-@AutoValue
-abstract class AndroidInjectorDescriptor {
- /** The type to be injected; the return type of the {@link ContributesAndroidInjector} method. */
- abstract ClassName injectedType();
-
- /** Scopes to apply to the generated {@link dagger.Subcomponent}. */
- abstract ImmutableSet<AnnotationSpec> scopes();
-
- /** @see ContributesAndroidInjector#modules() */
- abstract ImmutableSet<ClassName> modules();
-
- /** The {@link Module} that contains the {@link ContributesAndroidInjector} method. */
- abstract ClassName enclosingModule();
-
- /** The method annotated with {@link ContributesAndroidInjector}. */
- abstract ExecutableElement method();
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract Builder injectedType(ClassName injectedType);
-
- abstract ImmutableSet.Builder<AnnotationSpec> scopesBuilder();
-
- abstract ImmutableSet.Builder<ClassName> modulesBuilder();
-
- abstract Builder enclosingModule(ClassName enclosingModule);
-
- abstract Builder method(ExecutableElement method);
-
- abstract AndroidInjectorDescriptor build();
- }
-
- static final class Validator {
- private final Messager messager;
-
- Validator(Messager messager) {
- this.messager = messager;
- }
-
- /**
- * Validates a {@link ContributesAndroidInjector} method, returning an {@link
- * AndroidInjectorDescriptor} if it is valid, or {@link Optional#empty()} otherwise.
- */
- Optional<AndroidInjectorDescriptor> createIfValid(ExecutableElement method) {
- ErrorReporter reporter = new ErrorReporter(method, messager);
-
- if (!method.getModifiers().contains(ABSTRACT)) {
- reporter.reportError("@ContributesAndroidInjector methods must be abstract");
- }
-
- if (!method.getParameters().isEmpty()) {
- reporter.reportError("@ContributesAndroidInjector methods cannot have parameters");
- }
-
- AndroidInjectorDescriptor.Builder builder =
- new AutoValue_AndroidInjectorDescriptor.Builder().method(method);
- TypeElement enclosingElement = MoreElements.asType(method.getEnclosingElement());
- if (!isAnnotationPresent(enclosingElement, Module.class)) {
- reporter.reportError("@ContributesAndroidInjector methods must be in a @Module");
- }
- builder.enclosingModule(ClassName.get(enclosingElement));
-
- TypeMirror injectedType = method.getReturnType();
- if (MoreTypes.asDeclared(injectedType).getTypeArguments().isEmpty()) {
- builder.injectedType(ClassName.get(MoreTypes.asTypeElement(injectedType)));
- } else {
- reporter.reportError(
- "@ContributesAndroidInjector methods cannot return parameterized types");
- }
-
- AnnotationMirror annotation =
- getAnnotationMirror(method, ContributesAndroidInjector.class).get();
- for (TypeMirror module :
- getAnnotationValue(annotation, "modules").accept(new AllTypesVisitor(), null)) {
- if (isAnnotationPresent(MoreTypes.asElement(module), Module.class)) {
- builder.modulesBuilder().add((ClassName) TypeName.get(module));
- } else {
- reporter.reportError(String.format("%s is not a @Module", module), annotation);
- }
- }
-
- for (AnnotationMirror scope : getAnnotatedAnnotations(method, Scope.class)) {
- builder.scopesBuilder().add(AnnotationSpec.get(scope));
- }
-
- for (AnnotationMirror qualifier : getAnnotatedAnnotations(method, Qualifier.class)) {
- reporter.reportError(
- "@ContributesAndroidInjector methods cannot have qualifiers", qualifier);
- }
-
- return reporter.hasError ? Optional.empty() : Optional.of(builder.build());
- }
-
- // TODO(ronshapiro): use ValidationReport once it is moved out of the compiler
- private static class ErrorReporter {
- private final Element subject;
- private final Messager messager;
- private boolean hasError;
-
- ErrorReporter(Element subject, Messager messager) {
- this.subject = subject;
- this.messager = messager;
- }
-
- void reportError(String error) {
- hasError = true;
- messager.printMessage(Kind.ERROR, error, subject);
- }
-
- void reportError(String error, AnnotationMirror annotation) {
- hasError = true;
- messager.printMessage(Kind.ERROR, error, subject, annotation);
- }
- }
- }
-
- private static final class AllTypesVisitor
- extends SimpleAnnotationValueVisitor8<ImmutableSet<TypeMirror>, Void> {
- @Override
- public ImmutableSet<TypeMirror> visitArray(List<? extends AnnotationValue> values, Void aVoid) {
- return ImmutableSet.copyOf(
- values.stream().flatMap(v -> v.accept(this, null).stream()).collect(toList()));
- }
-
- @Override
- public ImmutableSet<TypeMirror> visitType(TypeMirror a, Void aVoid) {
- return ImmutableSet.of(a);
- }
-
- @Override
- protected ImmutableSet<TypeMirror> defaultAction(Object o, Void aVoid) {
- throw new AssertionError(o);
- }
- }
-}
diff --git a/java/dagger/android/processor/AndroidMapKeyValidator.java b/java/dagger/android/processor/AndroidMapKeyValidator.java
deleted file mode 100644
index f6e808a..0000000
--- a/java/dagger/android/processor/AndroidMapKeyValidator.java
+++ /dev/null
@@ -1,177 +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.android.processor;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.MoreElements.getAnnotationMirror;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.android.processor.AndroidMapKeys.injectedTypeFromMapKey;
-
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
-import dagger.Binds;
-import dagger.MapKey;
-import dagger.android.AndroidInjectionKey;
-import dagger.android.AndroidInjector;
-import dagger.multibindings.ClassKey;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Qualifier;
-import javax.inject.Scope;
-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;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic.Kind;
-
-/** Validates the correctness of {@link MapKey}s used with {@code dagger.android}. */
-final class AndroidMapKeyValidator implements ProcessingStep {
- private final Elements elements;
- private final Types types;
- private final Messager messager;
-
- AndroidMapKeyValidator(Elements elements, Types types, Messager messager) {
- this.elements = elements;
- this.types = types;
- this.messager = messager;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.<Class<? extends Annotation>>builder()
- .add(AndroidInjectionKey.class)
- .add(ClassKey.class)
- .build();
- }
-
- @Override
- public Set<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
- elementsByAnnotation
- .entries()
- .forEach(
- entry -> {
- try {
- validateMethod(entry.getKey(), MoreElements.asExecutable(entry.getValue()));
- } catch (TypeNotPresentException e) {
- deferredElements.add(entry.getValue());
- }
- });
- return deferredElements.build();
- }
-
- private void validateMethod(Class<? extends Annotation> annotation, ExecutableElement method) {
- if (!getAnnotatedAnnotations(method, Qualifier.class).isEmpty()) {
- return;
- }
-
- TypeMirror returnType = method.getReturnType();
- if (!types.isAssignable(types.erasure(returnType), factoryElement().asType())) {
- // if returnType is not related to AndroidInjector.Factory, ignore the method
- return;
- }
-
- if (!getAnnotatedAnnotations(method, Scope.class).isEmpty()) {
- SuppressWarnings suppressedWarnings = method.getAnnotation(SuppressWarnings.class);
- if (suppressedWarnings == null
- || !ImmutableSet.copyOf(suppressedWarnings.value())
- .contains("dagger.android.ScopedInjectorFactory")) {
- AnnotationMirror mapKeyAnnotation =
- getOnlyElement(getAnnotatedAnnotations(method, MapKey.class));
- TypeElement mapKeyValueElement =
- elements.getTypeElement(injectedTypeFromMapKey(mapKeyAnnotation).get());
- messager.printMessage(
- Kind.ERROR,
- String.format(
- "%s bindings should not be scoped. Scoping this method may leak instances of %s.",
- AndroidInjector.Factory.class.getCanonicalName(),
- mapKeyValueElement.getQualifiedName()),
- method);
- }
- }
-
- validateReturnType(method);
-
- // @Binds methods should only have one parameter, but we can't guarantee the order of Processors
- // in javac, so do a basic check for valid form
- if (isAnnotationPresent(method, Binds.class) && method.getParameters().size() == 1) {
- validateMapKeyMatchesBindsParameter(annotation, method);
- }
- }
-
- /** Report an error if the method's return type is not {@code AndroidInjector.Factory<?>}. */
- private void validateReturnType(ExecutableElement method) {
- TypeMirror returnType = method.getReturnType();
- DeclaredType requiredReturnType = injectorFactoryOf(types.getWildcardType(null, null));
-
- if (!types.isSameType(returnType, requiredReturnType)) {
- messager.printMessage(
- Kind.ERROR,
- String.format(
- "%s should bind %s, not %s. See https://dagger.dev/android",
- method, requiredReturnType, returnType),
- method);
- }
- }
-
- /**
- * A valid @Binds method could bind an {@link AndroidInjector.Factory} for one type, while giving
- * it a map key of a different type. The return type and parameter type would pass typical @Binds
- * validation, but the map lookup in {@link dagger.android.DispatchingAndroidInjector} would
- * retrieve the wrong injector factory.
- *
- * <pre>{@code
- * {@literal @Binds}
- * {@literal @IntoMap}
- * {@literal @ClassKey(GreenActivity.class)}
- * abstract AndroidInjector.Factory<?> bindBlueActivity(
- * BlueActivityComponent.Builder builder);
- * }</pre>
- */
- private void validateMapKeyMatchesBindsParameter(
- Class<? extends Annotation> annotation, ExecutableElement method) {
- TypeMirror parameterType = getOnlyElement(method.getParameters()).asType();
- AnnotationMirror annotationMirror = getAnnotationMirror(method, annotation).get();
- TypeMirror mapKeyType =
- elements.getTypeElement(injectedTypeFromMapKey(annotationMirror).get()).asType();
- if (!types.isAssignable(parameterType, injectorFactoryOf(mapKeyType))) {
- messager.printMessage(
- Kind.ERROR,
- String.format("%s does not implement AndroidInjector<%s>", parameterType, mapKeyType),
- method,
- annotationMirror);
- }
- }
-
- /** Returns a {@link DeclaredType} for {@code AndroidInjector.Factory<implementationType>}. */
- private DeclaredType injectorFactoryOf(TypeMirror implementationType) {
- return types.getDeclaredType(factoryElement(), implementationType);
- }
-
- private TypeElement factoryElement() {
- return elements.getTypeElement(AndroidInjector.Factory.class.getCanonicalName());
- }
-}
diff --git a/java/dagger/android/processor/AndroidMapKeys.java b/java/dagger/android/processor/AndroidMapKeys.java
deleted file mode 100644
index fb1fc38..0000000
--- a/java/dagger/android/processor/AndroidMapKeys.java
+++ /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.
- */
-
-package dagger.android.processor;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-
-import com.google.auto.common.MoreTypes;
-import dagger.android.AndroidInjectionKey;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-final class AndroidMapKeys {
- /**
- * If {@code mapKey} is {@link AndroidInjectionKey}, returns the string value for the map key. If
- * it's {@link dagger.multibindings.ClassKey}, returns the fully-qualified class name of the
- * annotation value. Otherwise returns {@link Optional#empty()}.
- */
- static Optional<String> injectedTypeFromMapKey(AnnotationMirror mapKey) {
- Object mapKeyClass = getAnnotationValue(mapKey, "value").getValue();
- if (mapKeyClass instanceof String) {
- return Optional.of((String) mapKeyClass);
- } else if (mapKeyClass instanceof TypeMirror) {
- TypeElement type = MoreTypes.asTypeElement((TypeMirror) mapKeyClass);
- return Optional.of(type.getQualifiedName().toString());
- } else {
- return Optional.empty();
- }
- }
-}
diff --git a/java/dagger/android/processor/AndroidProcessor.java b/java/dagger/android/processor/AndroidProcessor.java
deleted file mode 100644
index 5c17341..0000000
--- a/java/dagger/android/processor/AndroidProcessor.java
+++ /dev/null
@@ -1,132 +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.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;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/**
- * An {@linkplain javax.annotation.processing.Processor annotation processor} to verify usage of
- * {@code dagger.android} code.
- *
- * <p>Additionally, if {@code -Adagger.android.experimentalUseStringKeys} is passed to the
- * compilation, a file will be generated to support obfuscated injected Android types used with
- * {@code @AndroidInjectionKey}. The fact that this is generated is deliberate: not all versions of
- * ProGuard/R8 support {@code -identifiernamestring}, so we can't include a ProGuard file in the
- * dagger-android artifact Instead, we generate the file in {@code META-INF/proguard} only when
- * users enable the flag. They should only be enabling it if their shrinker supports those files,
- * and any version that does so will also support {@code -identifiernamestring}. This was added to
- * R8 in <a href="https://r8.googlesource.com/r8/+/389123dfcc11e6dda0eec31ab62e1b7eb0da80d2">May
- * 2018</a>.
- */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class AndroidProcessor extends BasicAnnotationProcessor {
- private static final String FLAG_EXPERIMENTAL_USE_STRING_KEYS =
- "dagger.android.experimentalUseStringKeys";
-
- @Override
- protected Iterable<? extends ProcessingStep> initSteps() {
- Filer filer = new FormattingFiler(processingEnv.getFiler());
- Messager messager = processingEnv.getMessager();
- Elements elements = processingEnv.getElementUtils();
- Types types = processingEnv.getTypeUtils();
-
- return ImmutableList.of(
- new AndroidMapKeyValidator(elements, types, messager),
- new ContributesAndroidInjectorGenerator(
- new AndroidInjectorDescriptor.Validator(messager),
- useStringKeys(),
- filer,
- elements,
- processingEnv.getSourceVersion()));
- }
-
- private boolean useStringKeys() {
- if (!processingEnv.getOptions().containsKey(FLAG_EXPERIMENTAL_USE_STRING_KEYS)) {
- return false;
- }
- String flagValue = processingEnv.getOptions().get(FLAG_EXPERIMENTAL_USE_STRING_KEYS);
- if (flagValue == null || Ascii.equalsIgnoreCase(flagValue, "true")) {
- return true;
- } else if (Ascii.equalsIgnoreCase(flagValue, "false")) {
- return false;
- } else {
- processingEnv
- .getMessager()
- .printMessage(
- ERROR,
- String.format(
- "Unknown flag value: %s. %s must be set to either 'true' or 'false'.",
- flagValue, FLAG_EXPERIMENTAL_USE_STRING_KEYS));
- return false;
- }
- }
-
- @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);
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latestSupported();
- }
-}
diff --git a/java/dagger/android/processor/BUILD b/java/dagger/android/processor/BUILD
deleted file mode 100644
index 5754143..0000000
--- a/java/dagger/android/processor/BUILD
+++ /dev/null
@@ -1,88 +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:
-# Public Dagger API for Android
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-load("//tools:maven.bzl", "POM_VERSION", "pom_file")
-
-filegroup(
- name = "srcs",
- srcs = glob(["*.java"]),
-)
-
-java_library(
- name = "processor",
- srcs = [":srcs"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- tags = ["maven_coordinates=com.google.dagger:dagger-android-processor:" + POM_VERSION],
- deps = [
- "@google_bazel_common//third_party/java/guava",
- "@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/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",
- ],
-)
-
-# https://github.com/bazelbuild/bazel/issues/2517
-# This target serves two (related) purposes:
-# 1. Bazel does not allow a java_library to depend on an android_library, even if that java_library
-# will be used in a java_plugin.
-# 2. It stores the metadata for the "jarimpl" target that we use to work-around Gradle not loading
-# aar artifacts that are declared as deps of an annotation processor. Our pom.xml generator reads
-# the tags and includes them apppropriately.
-java_import(
- name = "dagger-android-jar",
- jars = ["//java/dagger/android:libandroid.jar"],
- tags = ["maven_coordinates=com.google.dagger:dagger-android-jarimpl:" + POM_VERSION],
- visibility = ["//visibility:private"],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-android-processor",
- artifact_name = "Dagger Android Processor",
- targets = [":processor"],
-)
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.android.processor.AndroidProcessor",
- deps = [":processor"],
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "processor-javadoc",
- srcs = [":srcs"],
- root_packages = ["dagger.android.processor"],
- deps = [":processor"],
-)
diff --git a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java b/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
deleted file mode 100644
index 5c99fd4..0000000
--- a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java
+++ /dev/null
@@ -1,199 +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.android.processor;
-
-import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static com.squareup.javapoet.TypeSpec.interfaceBuilder;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-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.BasicAnnotationProcessor.ProcessingStep;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.WildcardTypeName;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjectionKey;
-import dagger.android.AndroidInjector;
-import dagger.android.ContributesAndroidInjector;
-import dagger.android.processor.AndroidInjectorDescriptor.Validator;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.util.Elements;
-
-/** Generates the implementation specified in {@link ContributesAndroidInjector}. */
-final class ContributesAndroidInjectorGenerator implements ProcessingStep {
-
- private final AndroidInjectorDescriptor.Validator validator;
- private final Filer filer;
- private final Elements elements;
- private final boolean useStringKeys;
- private final SourceVersion sourceVersion;
-
- ContributesAndroidInjectorGenerator(
- Validator validator,
- boolean useStringKeys,
- Filer filer,
- Elements elements,
- SourceVersion sourceVersion) {
- this.validator = validator;
- this.useStringKeys = useStringKeys;
- this.filer = filer;
- this.elements = elements;
- this.sourceVersion = sourceVersion;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(ContributesAndroidInjector.class);
- }
-
- @Override
- public Set<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
- for (ExecutableElement method : methodsIn(elementsByAnnotation.values())) {
- try {
- validator.createIfValid(method).ifPresent(this::generate);
- } catch (TypeNotPresentException e) {
- deferredElements.add(method);
- }
- }
- return deferredElements.build();
- }
-
- private void generate(AndroidInjectorDescriptor descriptor) {
- ClassName moduleName =
- descriptor
- .enclosingModule()
- .topLevelClassName()
- .peerClass(
- Joiner.on('_').join(descriptor.enclosingModule().simpleNames())
- + "_"
- + LOWER_CAMEL.to(UPPER_CAMEL, descriptor.method().getSimpleName().toString()));
-
- String baseName = descriptor.injectedType().simpleName();
- ClassName subcomponentName = moduleName.nestedClass(baseName + "Subcomponent");
- ClassName subcomponentFactoryName = subcomponentName.nestedClass("Factory");
-
- TypeSpec.Builder module =
- classBuilder(moduleName)
- .addOriginatingElement(descriptor.method())
- .addAnnotation(
- AnnotationSpec.builder(Module.class)
- .addMember("subcomponents", "$T.class", subcomponentName)
- .build())
- .addModifiers(PUBLIC, ABSTRACT)
- .addMethod(bindAndroidInjectorFactory(descriptor, subcomponentFactoryName))
- .addType(subcomponent(descriptor, subcomponentName, subcomponentFactoryName))
- .addMethod(constructorBuilder().addModifiers(PRIVATE).build());
- generatedAnnotationSpec(elements, sourceVersion, AndroidProcessor.class)
- .ifPresent(module::addAnnotation);
-
- try {
- JavaFile.builder(moduleName.packageName(), module.build())
- .skipJavaLangImports(true)
- .build()
- .writeTo(filer);
- } catch (IOException e) {
- throw new AssertionError(e);
- }
- }
-
- private MethodSpec bindAndroidInjectorFactory(
- AndroidInjectorDescriptor descriptor, ClassName subcomponentBuilderName) {
- return methodBuilder("bindAndroidInjectorFactory")
- .addAnnotation(Binds.class)
- .addAnnotation(IntoMap.class)
- .addAnnotation(androidInjectorMapKey(descriptor))
- .addModifiers(ABSTRACT)
- .returns(
- parameterizedTypeName(
- AndroidInjector.Factory.class,
- WildcardTypeName.subtypeOf(TypeName.OBJECT)))
- .addParameter(subcomponentBuilderName, "builder")
- .build();
- }
-
- private AnnotationSpec androidInjectorMapKey(AndroidInjectorDescriptor descriptor) {
- if (useStringKeys) {
- return AnnotationSpec.builder(AndroidInjectionKey.class)
- .addMember("value", "$S", descriptor.injectedType().toString())
- .build();
- }
- return AnnotationSpec.builder(ClassKey.class)
- .addMember("value", "$T.class", descriptor.injectedType())
- .build();
- }
-
- private TypeSpec subcomponent(
- AndroidInjectorDescriptor descriptor,
- ClassName subcomponentName,
- ClassName subcomponentFactoryName) {
- AnnotationSpec.Builder subcomponentAnnotation = AnnotationSpec.builder(Subcomponent.class);
- for (ClassName module : descriptor.modules()) {
- subcomponentAnnotation.addMember("modules", "$T.class", module);
- }
-
- return interfaceBuilder(subcomponentName)
- .addModifiers(PUBLIC)
- .addAnnotation(subcomponentAnnotation.build())
- .addAnnotations(descriptor.scopes())
- .addSuperinterface(parameterizedTypeName(AndroidInjector.class, descriptor.injectedType()))
- .addType(subcomponentFactory(descriptor, subcomponentFactoryName))
- .build();
- }
-
- private TypeSpec subcomponentFactory(
- AndroidInjectorDescriptor descriptor, ClassName subcomponentFactoryName) {
- return interfaceBuilder(subcomponentFactoryName)
- .addAnnotation(Subcomponent.Factory.class)
- .addModifiers(PUBLIC, STATIC)
- .addSuperinterface(
- parameterizedTypeName(AndroidInjector.Factory.class, descriptor.injectedType()))
- .build();
- }
-
- private static ParameterizedTypeName parameterizedTypeName(
- Class<?> clazz, TypeName... typeArguments) {
- return ParameterizedTypeName.get(ClassName.get(clazz), typeArguments);
- }
-}
diff --git a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java b/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java
deleted file mode 100644
index a19c5ef..0000000
--- a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.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.android.processor;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.android.processor.AndroidMapKeys.injectedTypeFromMapKey;
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toList;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimaps;
-import dagger.MapKey;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingKind;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.Formatter;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Stream;
-import javax.inject.Provider;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Validates that the two maps that {@link DispatchingAndroidInjector} injects have logically
- * different keys. If a contribution exists for the same {@code FooActivity} with
- * {@code @ActivityKey(FooActivity.class)} and
- * {@code @AndroidInjectionKey("com.example.FooActivity")}, report an error.
- */
-@AutoService(BindingGraphPlugin.class)
-public final class DuplicateAndroidInjectorsChecker implements BindingGraphPlugin {
- @Override
- public void visitGraph(BindingGraph graph, DiagnosticReporter diagnosticReporter) {
- for (Binding binding : graph.bindings()) {
- if (isDispatchingAndroidInjector(binding)) {
- validateMapKeyUniqueness(binding, graph, diagnosticReporter);
- }
- }
- }
-
- private boolean isDispatchingAndroidInjector(Binding binding) {
- Key key = binding.key();
- return MoreTypes.isTypeOf(DispatchingAndroidInjector.class, key.type())
- && !key.qualifier().isPresent();
- }
-
- private void validateMapKeyUniqueness(
- Binding dispatchingAndroidInjector,
- BindingGraph graph,
- DiagnosticReporter diagnosticReporter) {
- ImmutableSet<Binding> injectorFactories =
- injectorMapDependencies(dispatchingAndroidInjector, graph)
- .flatMap(injectorFactoryMap -> graph.requestedBindings(injectorFactoryMap).stream())
- .collect(collectingAndThen(toList(), ImmutableSet::copyOf));
-
- ImmutableListMultimap.Builder<String, Binding> mapKeyIndex = ImmutableListMultimap.builder();
- for (Binding injectorFactory : injectorFactories) {
- AnnotationMirror mapKey = mapKey(injectorFactory).get();
- Optional<String> injectedType = injectedTypeFromMapKey(mapKey);
- if (injectedType.isPresent()) {
- mapKeyIndex.put(injectedType.get(), injectorFactory);
- } else {
- diagnosticReporter.reportBinding(
- ERROR, injectorFactory, "Unrecognized class: %s", mapKey);
- }
- }
-
- Map<String, List<Binding>> duplicates =
- Maps.filterValues(Multimaps.asMap(mapKeyIndex.build()), bindings -> bindings.size() > 1);
- if (!duplicates.isEmpty()) {
- StringBuilder errorMessage =
- new StringBuilder("Multiple injector factories bound for the same type:\n");
- Formatter formatter = new Formatter(errorMessage);
- duplicates.forEach(
- (injectedType, duplicateFactories) -> {
- formatter.format(" %s:\n", injectedType);
- duplicateFactories.forEach(duplicate -> formatter.format(" %s\n", duplicate));
- });
- diagnosticReporter.reportBinding(ERROR, dispatchingAndroidInjector, errorMessage.toString());
- }
- }
-
- /**
- * Returns a stream of the dependencies of {@code binding} that have a key type of {@code Map<K,
- * Provider<AndroidInjector.Factory<?>>}.
- */
- private Stream<Binding> injectorMapDependencies(Binding binding, BindingGraph graph) {
- return graph.requestedBindings(binding).stream()
- .filter(requestedBinding -> requestedBinding.kind().equals(BindingKind.MULTIBOUND_MAP))
- .filter(
- requestedBinding -> {
- TypeMirror valueType =
- MoreTypes.asDeclared(requestedBinding.key().type()).getTypeArguments().get(1);
- if (!MoreTypes.isTypeOf(Provider.class, valueType)
- || !valueType.getKind().equals(TypeKind.DECLARED)) {
- return false;
- }
- TypeMirror providedType = MoreTypes.asDeclared(valueType).getTypeArguments().get(0);
- return MoreTypes.isTypeOf(AndroidInjector.Factory.class, providedType);
- });
- }
-
- private Optional<AnnotationMirror> mapKey(Binding binding) {
- return binding
- .bindingElement()
- .map(bindingElement -> getAnnotatedAnnotations(bindingElement, MapKey.class))
- .flatMap(
- annotations ->
- annotations.isEmpty()
- ? Optional.empty()
- : Optional.of(getOnlyElement(annotations)));
- }
-
- @Override
- public String pluginName() {
- return "Dagger/Android/DuplicateAndroidInjectors";
- }
-}
diff --git a/java/dagger/android/proguard.cfg b/java/dagger/android/proguard.cfg
deleted file mode 100644
index bd8ffbf..0000000
--- a/java/dagger/android/proguard.cfg
+++ /dev/null
@@ -1 +0,0 @@
--dontwarn com.google.errorprone.annotations.**
diff --git a/java/dagger/android/support/AndroidManifest.xml b/java/dagger/android/support/AndroidManifest.xml
deleted file mode 100644
index d080e11..0000000
--- a/java/dagger/android/support/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +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.android.support">
- <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/java/dagger/android/support/AndroidSupportInjection.java b/java/dagger/android/support/AndroidSupportInjection.java
deleted file mode 100644
index 1624345..0000000
--- a/java/dagger/android/support/AndroidSupportInjection.java
+++ /dev/null
@@ -1,111 +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.android.support;
-
-import static android.util.Log.DEBUG;
-import static dagger.internal.Preconditions.checkNotNull;
-
-import android.app.Activity;
-import android.app.Application;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import dagger.android.AndroidInjector;
-import dagger.android.HasAndroidInjector;
-import dagger.internal.Beta;
-
-/** Injects core Android types from support libraries. */
-@Beta
-public final class AndroidSupportInjection {
- private static final String TAG = "dagger.android.support";
-
- /**
- * 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 {@link AndroidInjector} to use to
- * inject {@code fragment}:
- *
- * <ol>
- * <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} 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} or {@link HasSupportFragmentInjector}, a
- * {@link IllegalArgumentException} is thrown.
- *
- * @throws IllegalArgumentException if no parent fragment, activity, or application implements
- * {@link HasAndroidInjector} or {@link HasSupportFragmentInjector}.
- */
- public static void inject(Fragment fragment) {
- checkNotNull(fragment, "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(),
- hasInjector.getClass().getCanonicalName()));
- }
-
- injector.inject(fragment);
- }
-
- private static Object findHasSupportFragmentInjector(Fragment fragment) {
- Fragment parentFragment = fragment;
- while ((parentFragment = parentFragment.getParentFragment()) != null) {
- if (parentFragment instanceof HasAndroidInjector
- || parentFragment instanceof HasSupportFragmentInjector) {
- return parentFragment;
- }
- }
- Activity activity = fragment.getActivity();
- if (activity instanceof HasAndroidInjector || activity instanceof HasSupportFragmentInjector) {
- return activity;
- }
- 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()));
- }
-
- private AndroidSupportInjection() {}
-}
diff --git a/java/dagger/android/support/AndroidSupportInjectionModule.java b/java/dagger/android/support/AndroidSupportInjectionModule.java
deleted file mode 100644
index d78b0cb..0000000
--- a/java/dagger/android/support/AndroidSupportInjectionModule.java
+++ /dev/null
@@ -1,31 +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.android.support;
-
-import dagger.Module;
-import dagger.android.AndroidInjectionModule;
-import dagger.internal.Beta;
-
-/**
- * This module no longer provides any value beyond what is provided in {@link
- * AndroidInjectionModule} and is just an alias. It will be removed in a future release.
- */
-@Beta
-@Module(includes = AndroidInjectionModule.class)
-public abstract class AndroidSupportInjectionModule {
- private AndroidSupportInjectionModule() {}
-}
diff --git a/java/dagger/android/support/BUILD b/java/dagger/android/support/BUILD
deleted file mode 100644
index 749d541..0000000
--- a/java/dagger/android/support/BUILD
+++ /dev/null
@@ -1,75 +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:
-# Public Dagger API for Android that interacts with the Android support libraries
-
-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"]),
-)
-
-android_library(
- name = "support",
- srcs = glob(["*.java"]),
- javacopts = SOURCE_7_TARGET_7,
- 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",
- ],
-)
-
-# 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",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-android-support",
- artifact_name = "Dagger Android Support",
- packaging = "aar",
- targets = [":support"],
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "support-javadoc",
- srcs = [":support-srcs"],
- 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
deleted file mode 100644
index ccc4faa..0000000
--- a/java/dagger/android/support/DaggerAppCompatActivity.java
+++ /dev/null
@@ -1,49 +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.android.support;
-
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AppCompatActivity;
-import dagger.android.AndroidInjection;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
-import dagger.android.HasAndroidInjector;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * An {@link AppCompatActivity} that injects its members in {@link #onCreate(Bundle)} and can be
- * used to inject {@code Fragment}s attached to it.
- */
-@Beta
-public abstract class DaggerAppCompatActivity extends AppCompatActivity
- implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- AndroidInjection.inject(this);
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/support/DaggerAppCompatDialogFragment.java b/java/dagger/android/support/DaggerAppCompatDialogFragment.java
deleted file mode 100644
index 1efaeec..0000000
--- a/java/dagger/android/support/DaggerAppCompatDialogFragment.java
+++ /dev/null
@@ -1,49 +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.android.support;
-
-import android.content.Context;
-import android.support.v4.app.Fragment;
-import android.support.v7.app.AppCompatDialogFragment;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
-import dagger.android.HasAndroidInjector;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * An {@link AppCompatDialogFragment} that injects its members in {@link #onAttach(Context)} and can
- * be used to inject child {@link Fragment}s attached to it. Note that when this fragment gets
- * reattached, its members will be injected again.
- */
-@Beta
-public abstract class DaggerAppCompatDialogFragment extends AppCompatDialogFragment
- implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onAttach(Context context) {
- AndroidSupportInjection.inject(this);
- super.onAttach(context);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/support/DaggerApplication.java b/java/dagger/android/support/DaggerApplication.java
deleted file mode 100644
index 1cb3bd8..0000000
--- a/java/dagger/android/support/DaggerApplication.java
+++ /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.
- */
-
-package dagger.android.support;
-
-import dagger.android.AndroidInjector;
-
-/**
- * An {@link Application} that injects its members and can be used to inject classes that the
- * Android framework instantiates. Injection is performed in {@link #onCreate()} or the first call
- * to {@link AndroidInjection#inject(ContentProvider)}, whichever happens first.
- */
-// TODO(ronshapiro): deprecate and remove this class
-public abstract class DaggerApplication extends dagger.android.DaggerApplication {
- @Override
- protected abstract AndroidInjector<? extends DaggerApplication> applicationInjector();
-}
diff --git a/java/dagger/android/support/DaggerDialogFragment.java b/java/dagger/android/support/DaggerDialogFragment.java
deleted file mode 100644
index 69b90bc..0000000
--- a/java/dagger/android/support/DaggerDialogFragment.java
+++ /dev/null
@@ -1,48 +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.android.support;
-
-import android.content.Context;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.Fragment;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
-import dagger.android.HasAndroidInjector;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * A {@link DialogFragment} that injects its members in {@link #onAttach(Context)} and can be used
- * to inject child {@link Fragment}s attached to it. Note that when this fragment gets reattached,
- * its members will be injected again.
- */
-@Beta
-public abstract class DaggerDialogFragment extends DialogFragment implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onAttach(Context context) {
- AndroidSupportInjection.inject(this);
- super.onAttach(context);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/support/DaggerFragment.java b/java/dagger/android/support/DaggerFragment.java
deleted file mode 100644
index 332cdaa..0000000
--- a/java/dagger/android/support/DaggerFragment.java
+++ /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.
- */
-
-package dagger.android.support;
-
-import android.content.Context;
-import android.support.v4.app.Fragment;
-import dagger.android.AndroidInjector;
-import dagger.android.DispatchingAndroidInjector;
-import dagger.android.HasAndroidInjector;
-import dagger.internal.Beta;
-import javax.inject.Inject;
-
-/**
- * A {@link Fragment} that injects its members in {@link #onAttach(Context)} and can be used to
- * inject child {@link Fragment}s attached to it. Note that when this fragment gets reattached, its
- * members will be injected again.
- */
-@Beta
-public abstract class DaggerFragment extends Fragment implements HasAndroidInjector {
-
- @Inject DispatchingAndroidInjector<Object> androidInjector;
-
- @Override
- public void onAttach(Context context) {
- AndroidSupportInjection.inject(this);
- super.onAttach(context);
- }
-
- @Override
- public AndroidInjector<Object> androidInjector() {
- return androidInjector;
- }
-}
diff --git a/java/dagger/android/support/HasSupportFragmentInjector.java b/java/dagger/android/support/HasSupportFragmentInjector.java
deleted file mode 100644
index e80609e..0000000
--- a/java/dagger/android/support/HasSupportFragmentInjector.java
+++ /dev/null
@@ -1,29 +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.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/android/support/package-info.java b/java/dagger/android/support/package-info.java
deleted file mode 100644
index d49d44d..0000000
--- a/java/dagger/android/support/package-info.java
+++ /dev/null
@@ -1,26 +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.
- */
-
-@CheckReturnValue
-package dagger.android.support;
-
-/**
- * Additions to the APIs in {@link dagger.android} for use with the <a
- * href="https://developer.android.com/topic/libraries/support-library">Android support
- * libraries</a>.
- */
-
-import com.google.errorprone.annotations.CheckReturnValue;
diff --git a/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java b/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java
deleted file mode 100644
index e98fe9b..0000000
--- a/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java
+++ /dev/null
@@ -1,70 +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.errorprone;
-
-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;
-import com.google.errorprone.fixes.SuggestedFix;
-import com.google.errorprone.matchers.Description;
-import com.google.errorprone.matchers.Matcher;
-import com.google.errorprone.matchers.Matchers;
-import com.google.errorprone.util.ASTHelpers;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.MemberSelectTree;
-import com.sun.tools.javac.code.Symbol;
-
-/** 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 "
- + "AndroidInjectionModule. This migration rewrites usages of the former to the latter.",
- severity = SUGGESTION)
-public final class AndroidSupportInjectionModuleMigrator extends BugChecker
- implements MemberSelectTreeMatcher {
- private static final Matcher<ExpressionTree> MODULE_CLASS_LITERAL =
- Matchers.classLiteral(
- (ExpressionTree expressionTree, VisitorState state) -> {
- Symbol symbol = ASTHelpers.getSymbol(expressionTree);
- if (symbol == null) {
- return false;
- }
- return symbol
- .getQualifiedName()
- .contentEquals("dagger.android.support.AndroidSupportInjectionModule");
- });
-
- @Override
- public Description matchMemberSelect(MemberSelectTree tree, VisitorState state) {
- if (MODULE_CLASS_LITERAL.matches(tree, state)) {
- return describeMatch(
- tree,
- SuggestedFix.builder()
- .replace(tree, "AndroidInjectionModule.class")
- .addImport("dagger.android.AndroidInjectionModule")
- .build());
- }
- return Description.NO_MATCH;
- }
-}
diff --git a/java/dagger/errorprone/BUILD b/java/dagger/errorprone/BUILD
deleted file mode 100644
index 408925a..0000000
--- a/java/dagger/errorprone/BUILD
+++ /dev/null
@@ -1,15 +0,0 @@
-# Description:
-# ErrorProne refactorings and static analysis for Dagger
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "errorprone",
- srcs = glob(["*.java"]),
- deps = [
- "//java/dagger:core",
- "@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/android/simple/AndroidManifest.xml b/java/dagger/example/android/simple/AndroidManifest.xml
deleted file mode 100644
index 711fb1e..0000000
--- a/java/dagger/example/android/simple/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +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.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
deleted file mode 100644
index 7396744..0000000
--- a/java/dagger/example/android/simple/BUILD
+++ /dev/null
@@ -1,42 +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 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
deleted file mode 100644
index 40ac8ee..0000000
--- a/java/dagger/example/android/simple/BuildModule.java
+++ /dev/null
@@ -1,31 +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.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
deleted file mode 100644
index f2aab2d..0000000
--- a/java/dagger/example/android/simple/MainActivity.java
+++ /dev/null
@@ -1,69 +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.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
deleted file mode 100644
index c52bb98..0000000
--- a/java/dagger/example/android/simple/Model.java
+++ /dev/null
@@ -1,29 +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.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
deleted file mode 100644
index ae3d42d..0000000
--- a/java/dagger/example/android/simple/SimpleApplication.java
+++ /dev/null
@@ -1,54 +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.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
deleted file mode 100644
index 37add1f..0000000
--- a/java/dagger/example/android/simple/res/layout/activity_main.xml
+++ /dev/null
@@ -1,31 +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"
- 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
deleted file mode 100644
index c4ba1fd..0000000
--- a/java/dagger/example/android/simple/res/values/strings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?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/spi/BUILD b/java/dagger/example/spi/BUILD
deleted file mode 100644
index 84b4a87..0000000
--- a/java/dagger/example/spi/BUILD
+++ /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.
-
-# Description:
-# An example of the dagger.spi.BindingGraphPlugin usage
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "binding-graph-visualizer",
- srcs = glob(["*.java"]),
- deps = [
- "//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/example/spi/BindingGraphVisualizer.java b/java/dagger/example/spi/BindingGraphVisualizer.java
deleted file mode 100644
index e83fa2e..0000000
--- a/java/dagger/example/spi/BindingGraphVisualizer.java
+++ /dev/null
@@ -1,313 +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.example.spi;
-
-import static java.util.UUID.randomUUID;
-import static java.util.regex.Matcher.quoteReplacement;
-import static java.util.stream.Collectors.groupingBy;
-
-import com.google.auto.service.AutoService;
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
-import com.google.common.graph.EndpointPair;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.squareup.javapoet.ClassName;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import javax.annotation.processing.Filer;
-import javax.lang.model.element.TypeElement;
-import javax.tools.FileObject;
-import javax.tools.StandardLocation;
-
-/**
- * Experimental visualizer used as a proof-of-concept for {@link BindingGraphPlugin}.
- *
- * <p>For each component, writes a <a href=http://www.graphviz.org/content/dot-language>DOT file</a>
- * in the same package. The file name is the name of the component type (with enclosing type names,
- * joined by underscores, preceding it), with a {@code .dot} extension.
- *
- * <p>For example, for a nested component type {@code Foo.Bar} this will generate a file {@code
- * Foo_Bar.dot}.
- */
-@AutoService(BindingGraphPlugin.class)
-public final class BindingGraphVisualizer implements BindingGraphPlugin {
- private Filer filer;
-
- @Override
- public void initFiler(Filer filer) {
- this.filer = filer;
- }
-
- /** Graphviz color names to use for binding nodes within each component. */
- private static final ImmutableList<String> COMPONENT_COLORS =
- ImmutableList.of(
- "/set312/1",
- "/set312/2",
- "/set312/3",
- "/set312/4",
- "/set312/5",
- "/set312/6",
- "/set312/7",
- "/set312/8",
- "/set312/9",
- "/set312/10",
- "/set312/11",
- "/set312/12");
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- TypeElement componentElement =
- bindingGraph.rootComponentNode().componentPath().currentComponent();
- DotGraph graph = new NodesGraph(bindingGraph).graph();
- ClassName componentName = ClassName.get(componentElement);
- try {
- FileObject file =
- filer
- .createResource(
- StandardLocation.CLASS_OUTPUT,
- componentName.packageName(),
- Joiner.on('_').join(componentName.simpleNames()) + ".dot",
- componentElement);
- try (PrintWriter writer = new PrintWriter(file.openWriter())) {
- graph.write(0, writer);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private abstract static class Indented {
-
- abstract void write(int level, PrintWriter writer);
-
- @CanIgnoreReturnValue
- PrintWriter indent(int level, PrintWriter writer) {
- writer.print(Strings.repeat(" ", level * 2));
- return writer;
- }
- }
-
- static class DotGraph extends Indented {
- private final String header;
- private final List<Indented> elements = new ArrayList<>();
-
- DotGraph(String header) {
- this.header = header;
- }
-
- @CanIgnoreReturnValue
- DotGraph add(Indented element) {
- elements.add(element);
- return this;
- }
-
- @Override
- void write(int level, PrintWriter writer) {
- indent(level, writer);
- writer.println(header + " {");
- for (Indented element : elements) {
- element.write(level + 1, writer);
- }
- indent(level, writer);
- writer.println("}");
- }
- }
-
- static class DotStatement<S extends DotStatement<S>> extends Indented {
- private final String base;
- private final Map<String, Object> attributes = new LinkedHashMap<>();
-
- DotStatement(String base) {
- this.base = base;
- }
-
- @SuppressWarnings("unchecked")
- @CanIgnoreReturnValue
- S addAttribute(String name, Object value) {
- attributes.put(name, value);
- return (S) this;
- }
-
- @CanIgnoreReturnValue
- S addAttributeFormat(String name, String format, Object... args) {
- return addAttribute(name, String.format(format, args));
- }
-
- @Override
- void write(int level, PrintWriter writer) {
- indent(level, writer);
- writer.print(base);
- if (!attributes.isEmpty()) {
- writer.print(
- attributes
- .entrySet()
- .stream()
- .map(
- entry ->
- String.format("%s=%s", entry.getKey(), quote(entry.getValue().toString())))
- .collect(Collectors.joining(", ", " [", "]")));
- }
- writer.println();
- }
- }
-
- private static String quote(String string) {
- return '"' + string.replaceAll("\"", quoteReplacement("\\\"")) + '"';
- }
-
- static class DotNode extends DotStatement<DotNode> {
- DotNode(Object nodeName) {
- super(quote(nodeName.toString()));
- }
- }
-
- static class DotEdge extends DotStatement<DotEdge> {
- DotEdge(Object leftNode, Object rightNode) {
- super(quote(leftNode.toString()) + " -> " + quote(rightNode.toString()));
- }
- }
-
- static class NodesGraph {
- private final DotGraph graph =
- new DotGraph("digraph")
- .add(
- new DotStatement<>("graph")
- .addAttribute("rankdir", "LR")
- .addAttribute("labeljust", "l")
- .addAttribute("compound", true));
-
- private final BindingGraph bindingGraph;
- private final Map<Node, UUID> nodeIds = new HashMap<>();
-
- NodesGraph(BindingGraph bindingGraph) {
- this.bindingGraph = bindingGraph;
- }
-
- DotGraph graph() {
- if (nodeIds.isEmpty()) {
- Iterator<String> colors = Iterators.cycle(COMPONENT_COLORS);
- bindingGraph.network().nodes().stream()
- .collect(groupingBy(Node::componentPath))
- .forEach(
- (component, networkNodes) -> {
- DotGraph subgraph = subgraph(component);
- subgraph.add(
- new DotStatement<>("node")
- .addAttribute("style", "filled")
- .addAttribute("shape", "box")
- .addAttribute("fillcolor", colors.next()));
- subgraph.add(new DotStatement<>("graph").addAttribute("label", component));
- for (Node node : networkNodes) {
- subgraph.add(dotNode(node));
- }
- });
- for (Edge edge : bindingGraph.network().edges()) {
- dotEdge(edge).ifPresent(graph::add);
- }
- }
- return graph;
- }
-
- DotGraph subgraph(ComponentPath component) {
- DotGraph subgraph = new DotGraph("subgraph " + quote(clusterName(component)));
- graph.add(subgraph);
- return subgraph;
- }
-
- UUID nodeId(Node node) {
- return nodeIds.computeIfAbsent(node, n -> randomUUID());
- }
-
- Optional<DotEdge> dotEdge(Edge edge) {
- EndpointPair<Node> incidentNodes = bindingGraph.network().incidentNodes(edge);
- DotEdge dotEdge = new DotEdge(nodeId(incidentNodes.source()), nodeId(incidentNodes.target()));
- if (edge instanceof DependencyEdge) {
- if (((DependencyEdge) edge).isEntryPoint()) {
- return Optional.empty();
- }
- } else if (edge instanceof ChildFactoryMethodEdge) {
- dotEdge.addAttribute("style", "dashed");
- dotEdge.addAttribute("lhead", clusterName(incidentNodes.target().componentPath()));
- dotEdge.addAttribute("ltail", clusterName(incidentNodes.source().componentPath()));
- dotEdge.addAttribute("taillabel", ((ChildFactoryMethodEdge) edge).factoryMethod());
- } else if (edge instanceof SubcomponentCreatorBindingEdge) {
- dotEdge.addAttribute("style", "dashed");
- dotEdge.addAttribute("lhead", clusterName(incidentNodes.target().componentPath()));
- dotEdge.addAttribute("taillabel", "subcomponent");
- }
- return Optional.of(dotEdge);
- }
-
- DotNode dotNode(Node node) {
- DotNode dotNode = new DotNode(nodeId(node));
- if (node instanceof MaybeBinding) {
- dotNode.addAttribute("tooltip", "");
- if (bindingGraph.entryPointBindings().contains(node)) {
- dotNode.addAttribute("penwidth", 3);
- }
- if (node instanceof Binding) {
- dotNode.addAttribute("label", label((Binding) node));
- }
- if (node instanceof MissingBinding) {
- dotNode.addAttributeFormat(
- "label", "missing binding for %s", ((MissingBinding) node).key());
- }
- } else {
- dotNode.addAttribute("style", "invis").addAttribute("shape", "point");
- }
- return dotNode;
- }
-
- private String label(Binding binding) {
- if (binding.kind().equals(BindingKind.MEMBERS_INJECTION)) {
- return String.format("inject(%s)", binding.key());
- } else if (binding.isProduction()) {
- return String.format("@Produces %s", binding.key());
- } else {
- return binding.key().toString();
- }
- }
-
- private static String clusterName(ComponentPath owningComponentPath) {
- return "cluster" + owningComponentPath;
- }
- }
-}
diff --git a/java/dagger/grpc/server/BUILD b/java/dagger/grpc/server/BUILD
deleted file mode 100644
index 1c57807..0000000
--- a/java/dagger/grpc/server/BUILD
+++ /dev/null
@@ -1,77 +0,0 @@
-# A framework supporting Dagger-injected gRPC servers.
-
-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",
- "GrpcService.java",
-]
-
-java_library(
- name = "annotations",
- srcs = ANNOTATIONS_SRCS,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server-annotations:" + POM_VERSION],
- deps = [
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-# TODO(dpb): Split out the grpc:inprocess and grpc:netty deps into separate libraries.
-java_library(
- name = "server",
- srcs = glob(
- ["*.java"],
- exclude = ANNOTATIONS_SRCS,
- ),
- exported_plugins = ["//java/dagger/grpc/server/processor:plugin"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server:" + POM_VERSION],
- exports = [":annotations"],
- deps = [
- "//:dagger_with_compiler",
- "@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",
- ],
-)
-
-pom_file(
- name = "annotations-pom",
- artifact_id = "dagger-grpc-server-annotations",
- artifact_name = "Dagger gRPC Server Annotations",
- targets = [":annotations"],
-)
-
-pom_file(
- name = "server-pom",
- artifact_id = "dagger-grpc-server",
- artifact_name = "Dagger gRPC Server",
- targets = [":server"],
-)
-
-filegroup(
- name = "javadoc-srcs",
- srcs = glob(["*.java"]),
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "javadoc",
- srcs = [":javadoc-srcs"],
- root_packages = ["dagger.grpc.server"],
- deps = [
- ":annotations",
- ":server",
- ],
-)
diff --git a/java/dagger/grpc/server/CallScoped.java b/java/dagger/grpc/server/CallScoped.java
deleted file mode 100644
index 4b9d14f..0000000
--- a/java/dagger/grpc/server/CallScoped.java
+++ /dev/null
@@ -1,29 +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.grpc.server;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/** A scope that lasts as long as a single gRPC {@link io.grpc.ServerCall}. */
-@Retention(RUNTIME)
-@Scope
-@Documented
-public @interface CallScoped {}
diff --git a/java/dagger/grpc/server/CurrentContextModule.java b/java/dagger/grpc/server/CurrentContextModule.java
deleted file mode 100644
index c117537..0000000
--- a/java/dagger/grpc/server/CurrentContextModule.java
+++ /dev/null
@@ -1,33 +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.grpc.server;
-
-import dagger.Module;
-import dagger.Provides;
-import io.grpc.Context;
-
-/**
- * Provides the current {@link Context}.
- */
-@Module
-public final class CurrentContextModule {
-
- @Provides
- static Context currentContext() {
- return Context.current();
- }
-}
diff --git a/java/dagger/grpc/server/ForGrpcService.java b/java/dagger/grpc/server/ForGrpcService.java
deleted file mode 100644
index 33a83ad..0000000
--- a/java/dagger/grpc/server/ForGrpcService.java
+++ /dev/null
@@ -1,32 +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.grpc.server;
-
-import java.lang.annotation.Documented;
-import javax.inject.Qualifier;
-
-/**
- * Qualifies some per-service types provided by {@link dagger.Module}s generated by {@link
- * GrpcService}.
- */
-@Documented
-@Qualifier
-public @interface ForGrpcService {
-
- /** The gRPC service class. */
- Class<?> value();
-}
diff --git a/java/dagger/grpc/server/GrpcCallMetadataModule.java b/java/dagger/grpc/server/GrpcCallMetadataModule.java
deleted file mode 100644
index 8d474d9..0000000
--- a/java/dagger/grpc/server/GrpcCallMetadataModule.java
+++ /dev/null
@@ -1,40 +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.grpc.server;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import dagger.Module;
-import dagger.Provides;
-import io.grpc.Metadata;
-
-/**
- * Provides {@link Metadata} about a gRPC call.
- */
-@Module
-public final class GrpcCallMetadataModule {
- private final Metadata metadata;
-
- public GrpcCallMetadataModule(Metadata metadata) {
- this.metadata = checkNotNull(metadata);
- }
-
- @Provides
- Metadata provideHeaders() {
- return metadata;
- }
-}
diff --git a/java/dagger/grpc/server/GrpcService.java b/java/dagger/grpc/server/GrpcService.java
deleted file mode 100644
index a746195..0000000
--- a/java/dagger/grpc/server/GrpcService.java
+++ /dev/null
@@ -1,54 +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.grpc.server;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a class that implements a gRPC service.
- *
- * <p>Generates several types when annotating a class {@code Foo}:
- *
- * <ul>
- * <li>Interfaces {@code FooComponent} and {@code FooComponent.Factory}.
- * <li>{@linkplain dagger.Module Modules} {@code FooGrpcProxyModule} and {@code
- * FooGrpcServiceModule}.
- * </ul>
- *
- * <p>To use these types to configure a server:
- *
- * <ol>
- * <li>Create a {@linkplain dagger.Subcomponent subcomponent} that implements {@code FooComponent}
- * and installs {@code FooGrpcServiceModule}.
- * <li>Install {@link NettyServerModule} or another {@link ServerModule} subclass and {@code
- * FooGrpcProxyModule} into your {@link javax.inject.Singleton @Singleton} {@linkplain
- * dagger.Component component}.
- * <li>Bind an implementation of {@code FooComponent.Factory} in your {@link
- * javax.inject.Singleton @Singleton} {@linkplain dagger.Component component}. The
- * implementation will typically inject the {@link javax.inject.Singleton @Singleton}
- * {@linkplain dagger.Component component} and call subcomponent factory methods to instantiate
- * the correct subcomponent.
- * </ol>
- */
-@Documented
-@Target(ElementType.TYPE)
-public @interface GrpcService {
- /** The class that gRPC generates from the proto service definition. */
- Class<?> grpcClass();
-}
diff --git a/java/dagger/grpc/server/InProcessServerModule.java b/java/dagger/grpc/server/InProcessServerModule.java
deleted file mode 100644
index fd93382..0000000
--- a/java/dagger/grpc/server/InProcessServerModule.java
+++ /dev/null
@@ -1,54 +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.grpc.server;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import dagger.Module;
-import dagger.Provides;
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-import io.grpc.inprocess.InProcessServerBuilder;
-import javax.inject.Singleton;
-
-/**
- * Installing this module into a {@link Singleton @Singleton} component means the component can
- * provide a {@link Server} that serves {@linkplain InProcessServerBuilder in-process} requests.
- */
-@Module(includes = ServerModule.class)
-public final class InProcessServerModule {
-
- private final String name;
-
- private InProcessServerModule(String name) {
- this.name = checkNotNull(name);
- }
-
- /**
- * Creates a module that provides a server that binds to a given name
- *
- * @param name the identity of the server for clients to connect to
- */
- public static InProcessServerModule serverNamed(String name) {
- return new InProcessServerModule(name);
- }
-
- @Provides
- ServerBuilder<?> serverBuilder() {
- return InProcessServerBuilder.forName(name);
- }
-}
diff --git a/java/dagger/grpc/server/NettyServerModule.java b/java/dagger/grpc/server/NettyServerModule.java
deleted file mode 100644
index 4361d62..0000000
--- a/java/dagger/grpc/server/NettyServerModule.java
+++ /dev/null
@@ -1,59 +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.grpc.server;
-
-import dagger.Module;
-import dagger.Provides;
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-import io.grpc.netty.NettyServerBuilder;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import javax.inject.Singleton;
-
-/**
- * Installing this module into a {@link Singleton @Singleton} component means the component can
- * provide a {@linkplain NettyServerBuilder Netty}-based {@link Server}.
- */
-@Module(includes = ServerModule.class)
-public final class NettyServerModule {
-
- private final SocketAddress socketAddress;
-
- private NettyServerModule(SocketAddress socketAddress) {
- this.socketAddress = socketAddress;
- }
-
- /**
- * A module that binds to {@code port} on the wildcard address.
- */
- public static NettyServerModule bindingToPort(int port) {
- return new NettyServerModule(new InetSocketAddress(port));
- }
-
- /**
- * A module that binds to {@code socketAddress}.
- */
- public static NettyServerModule bindingTo(SocketAddress socketAddress) {
- return new NettyServerModule(socketAddress);
- }
-
- @Provides
- ServerBuilder<?> serverBuilder() {
- return NettyServerBuilder.forAddress(socketAddress);
- }
-}
diff --git a/java/dagger/grpc/server/ProxyServerCallHandler.java b/java/dagger/grpc/server/ProxyServerCallHandler.java
deleted file mode 100644
index 751d8ca..0000000
--- a/java/dagger/grpc/server/ProxyServerCallHandler.java
+++ /dev/null
@@ -1,191 +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.grpc.server;
-
-import io.grpc.Metadata;
-import io.grpc.MethodDescriptor;
-import io.grpc.MethodDescriptor.Marshaller;
-import io.grpc.ServerCall;
-import io.grpc.ServerCall.Listener;
-import io.grpc.ServerCallHandler;
-import io.grpc.ServerMethodDefinition;
-import io.grpc.ServerServiceDefinition;
-import io.grpc.Status;
-import java.io.InputStream;
-
-/**
- * A {@link ServerCallHandler} that handles calls for a particular method by delegating to a handler
- * in a {@link ServerServiceDefinition} returned by a factory.
- *
- * @param <RequestT> the type of the request payloads
- * @param <ResponseT> the type of the response payloads
- */
-public final class ProxyServerCallHandler<RequestT, ResponseT>
- implements ServerCallHandler<InputStream, InputStream> {
-
- /**
- * A factory for the {@link ServerServiceDefinition} that a {@link ProxyServerCallHandler}
- * delegates to.
- */
- public interface ServiceDefinitionFactory {
- /**
- * Returns a service definition that contains a {@link ServerCallHandler} for the
- * {@link ProxyServerCallHandler}'s method.
- */
- ServerServiceDefinition getServiceDefinition(Metadata headers);
- }
-
- private final MethodDescriptor<RequestT, ResponseT> delegateMethodDescriptor;
- private final ServiceDefinitionFactory delegateServiceDefinitionFactory;
-
- /**
- * Returns a proxy method definition for {@code methodDescriptor}.
- *
- * @param delegateServiceDefinitionFactory factory for the delegate service definition
- */
- public static <RequestT, ResponseT> ServerMethodDefinition<InputStream, InputStream> proxyMethod(
- MethodDescriptor<RequestT, ResponseT> delegateMethodDescriptor,
- ServiceDefinitionFactory delegateServiceDefinitionFactory) {
- return ServerMethodDefinition.create(
- MethodDescriptor.create(
- delegateMethodDescriptor.getType(),
- delegateMethodDescriptor.getFullMethodName(),
- IDENTITY_MARSHALLER,
- IDENTITY_MARSHALLER),
- new ProxyServerCallHandler<>(delegateMethodDescriptor, delegateServiceDefinitionFactory));
- }
-
- ProxyServerCallHandler(
- MethodDescriptor<RequestT, ResponseT> delegateMethodDescriptor,
- ServiceDefinitionFactory delegateServiceDefinitionFactory) {
- this.delegateMethodDescriptor = delegateMethodDescriptor;
- this.delegateServiceDefinitionFactory = delegateServiceDefinitionFactory;
- }
-
- @Override
- public Listener<InputStream> startCall(
- ServerCall<InputStream, InputStream> call,
- Metadata headers) {
- ServerMethodDefinition<RequestT, ResponseT> delegateMethod = getMethodDefinition(headers);
- Listener<RequestT> delegateListener =
- delegateMethod
- .getServerCallHandler()
- .startCall(new ServerCallAdapter(call, delegateMethod.getMethodDescriptor()), headers);
- return new ServerCallListenerAdapter(delegateListener);
- }
-
- @SuppressWarnings("unchecked") // Method definition is the correct type.
- private ServerMethodDefinition<RequestT, ResponseT> getMethodDefinition(Metadata headers) {
- String fullMethodName = delegateMethodDescriptor.getFullMethodName();
- for (ServerMethodDefinition<?, ?> methodDefinition :
- delegateServiceDefinitionFactory.getServiceDefinition(headers).getMethods()) {
- if (methodDefinition.getMethodDescriptor().getFullMethodName().equals(fullMethodName)) {
- return (ServerMethodDefinition<RequestT, ResponseT>) methodDefinition;
- }
- }
- throw new IllegalStateException("Could not find " + fullMethodName);
- }
-
- private static final Marshaller<InputStream> IDENTITY_MARSHALLER =
- new Marshaller<InputStream>() {
- @Override
- public InputStream stream(InputStream value) {
- return value;
- }
-
- @Override
- public InputStream parse(InputStream stream) {
- return stream;
- }
- };
-
- /** A {@link Listener} that adapts {@code Listener<RequestT>} to {@code Listener<InputStream>}. */
- private final class ServerCallListenerAdapter extends Listener<InputStream> {
-
- private final Listener<RequestT> delegate;
-
- public ServerCallListenerAdapter(Listener<RequestT> delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void onMessage(InputStream message) {
- delegate.onMessage(delegateMethodDescriptor.parseRequest(message));
- }
-
- @Override
- public void onHalfClose() {
- delegate.onHalfClose();
- }
-
- @Override
- public void onCancel() {
- delegate.onCancel();
- }
-
- @Override
- public void onComplete() {
- delegate.onComplete();
- }
- }
-
- /**
- * A {@link ServerCall} that adapts {@code ServerCall<InputStream>} to {@code
- * ServerCall<ResponseT>}.
- */
- final class ServerCallAdapter extends ServerCall<RequestT, ResponseT> {
-
- private final ServerCall<InputStream, InputStream> delegate;
- private final MethodDescriptor<RequestT, ResponseT> method;
-
- ServerCallAdapter(ServerCall<InputStream, InputStream> delegate,
- MethodDescriptor<RequestT, ResponseT> method) {
- this.delegate = delegate;
- this.method = method;
- }
-
- @Override
- public MethodDescriptor<RequestT, ResponseT> getMethodDescriptor() {
- return method;
- }
-
- @Override
- public void request(int numMessages) {
- delegate.request(numMessages);
- }
-
- @Override
- public void sendHeaders(Metadata headers) {
- delegate.sendHeaders(headers);
- }
-
- @Override
- public void sendMessage(ResponseT message) {
- delegate.sendMessage(delegateMethodDescriptor.streamResponse(message));
- }
-
- @Override
- public void close(Status status, Metadata trailers) {
- delegate.close(status, trailers);
- }
-
- @Override
- public boolean isCancelled() {
- return delegate.isCancelled();
- }
- }
-}
diff --git a/java/dagger/grpc/server/README.md b/java/dagger/grpc/server/README.md
deleted file mode 100644
index 5fe8d5c..0000000
--- a/java/dagger/grpc/server/README.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Dagger-gRPC on the Server
-
-This package contains the public types used to create gRPC server applications
-using https://dagger.dev.
-
-It is maintained by the Dagger team.
-
-It is in development, and is planned for open-source release as part of Dagger.
-
-See user documentation at https://dagger.dev/grpc.
diff --git a/java/dagger/grpc/server/ServerModule.java b/java/dagger/grpc/server/ServerModule.java
deleted file mode 100644
index f03f997..0000000
--- a/java/dagger/grpc/server/ServerModule.java
+++ /dev/null
@@ -1,42 +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.grpc.server;
-
-import dagger.Module;
-import dagger.Provides;
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-import io.grpc.ServerServiceDefinition;
-import java.util.Set;
-import javax.inject.Singleton;
-
-/**
- * Provides a {@link Singleton @Singleton} {@link Server}.
- */
-@Module
-public final class ServerModule {
-
- @Provides
- @Singleton
- static Server provideServer(
- ServerBuilder<?> serverBuilder, Set<ServerServiceDefinition> serviceDefinitions) {
- for (ServerServiceDefinition serverServiceDefinition : serviceDefinitions) {
- serverBuilder.addService(serverServiceDefinition);
- }
- return serverBuilder.build();
- }
-}
diff --git a/java/dagger/grpc/server/processor/BUILD b/java/dagger/grpc/server/processor/BUILD
deleted file mode 100644
index ce02b06..0000000
--- a/java/dagger/grpc/server/processor/BUILD
+++ /dev/null
@@ -1,49 +0,0 @@
-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"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- tags = ["maven_coordinates=com.google.dagger:dagger-grpc-server-processor:" + POM_VERSION],
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/grpc/server:annotations",
- "@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",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-grpc-server-processor",
- artifact_name = "Dagger gRPC Server Processor",
- targets = [":processor"],
-)
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.grpc.server.processor.GrpcServiceProcessor",
- deps = [":processor"],
-)
-
-filegroup(
- name = "javadoc-srcs",
- srcs = glob(["*.java"]),
-)
-
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
- name = "javadoc",
- srcs = [":javadoc-srcs"],
- root_packages = ["dagger.grpc.server.processor"],
- deps = [":processor"],
-)
diff --git a/java/dagger/grpc/server/processor/GrpcServiceModel.java b/java/dagger/grpc/server/processor/GrpcServiceModel.java
deleted file mode 100644
index 65d6903..0000000
--- a/java/dagger/grpc/server/processor/GrpcServiceModel.java
+++ /dev/null
@@ -1,192 +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.grpc.server.processor;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
-import static com.google.auto.common.MoreElements.getAnnotationMirror;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Joiner;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import dagger.grpc.server.ForGrpcService;
-import dagger.grpc.server.GrpcService;
-import dagger.grpc.server.processor.SourceGenerator.IoGrpc;
-import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.AnnotationValueVisitor;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleAnnotationValueVisitor7;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic.Kind;
-
-class GrpcServiceModel {
-
- private static final String GRPC_SERVICE_PARAMETER_NAME = "grpcClass";
-
- private final Types types;
- private final Elements elements;
- private final SourceVersion sourceVersion;
- private final Messager messager;
- final TypeElement serviceImplementation;
- final ClassName serviceImplementationClassName;
- final ClassName serviceDefinitionTypeName;
- final ClassName proxyModuleName;
- final ClassName serviceDefinitionTypeFactoryName;
- final ClassName serviceModuleName;
- final ClassName unscopedServiceModuleName;
-
- GrpcServiceModel(ProcessingEnvironment processingEnv, TypeElement serviceImplementation) {
- this.types = processingEnv.getTypeUtils();
- this.elements = processingEnv.getElementUtils();
- this.sourceVersion = processingEnv.getSourceVersion();
- this.messager = processingEnv.getMessager();
- this.serviceImplementation = serviceImplementation;
- this.serviceImplementationClassName = ClassName.get(serviceImplementation);
- this.serviceDefinitionTypeName = peerClassWithSuffix("ServiceDefinition");
- this.serviceDefinitionTypeFactoryName = serviceDefinitionTypeName.nestedClass("Factory");
- this.proxyModuleName = peerClassWithSuffix("GrpcProxyModule");
- this.serviceModuleName = peerClassWithSuffix("GrpcServiceModule");
- this.unscopedServiceModuleName = peerClassWithSuffix("UnscopedGrpcServiceModule");
- }
-
- /**
- * Returns the name of a top-level class in the same package as the service implementation
- * class, whose name is the simple name of the service implementation class and its enclosing
- * classes, joined with underscores, and appended with {@code suffix}.
- */
- private ClassName peerClassWithSuffix(String suffix) {
- return serviceImplementationClassName.peerClass(
- Joiner.on('_').join(serviceImplementationClassName.simpleNames()) + suffix);
- }
-
- String packageName() {
- return serviceImplementationClassName.packageName();
- }
-
- public boolean validate() {
- AnnotationValue argument =
- getAnnotationValue(grpcServiceAnnotation(), GRPC_SERVICE_PARAMETER_NAME);
- return argument.accept(
- new SimpleAnnotationValueVisitor7<Boolean, AnnotationValue>(false) {
- @Override
- public Boolean visitType(TypeMirror type, AnnotationValue value) {
- return validateGrpcClass(type, value);
- }
- },
- argument);
- }
-
- private AnnotationMirror grpcServiceAnnotation() {
- return getAnnotationMirror(serviceImplementation, GrpcService.class).get();
- }
-
- /** Returns the gRPC service class declared by {@link GrpcService#grpcClass()}. */
- protected final TypeElement grpcClass() {
- AnnotationValue argument =
- getAnnotationValue(grpcServiceAnnotation(), GRPC_SERVICE_PARAMETER_NAME);
- return GET_TYPE_ELEMENT_FROM_VALUE.visit(argument, argument);
- }
-
- /**
- * Returns the annotation spec for the {@code @Generated} annotation to add to any
- * type generated by this processor.
- */
- protected final Optional<AnnotationSpec> generatedAnnotation() {
- return generatedAnnotationSpec(
- elements,
- sourceVersion,
- GrpcService.class,
- String.format(
- "@%s annotation on %s",
- GrpcService.class.getCanonicalName(), serviceImplementationClassName));
- }
-
- /**
- * Returns the annotation spec for a {@link ForGrpcService} annotation whose value is the
- * gRPC-generated service class.
- */
- protected final AnnotationSpec forGrpcService() {
- return AnnotationSpec.builder(ForGrpcService.class)
- .addMember("value", "$T.class", grpcClass())
- .build();
- }
-
- protected final String subcomponentServiceDefinitionMethodName() {
- return UPPER_CAMEL.to(LOWER_CAMEL, simpleServiceName()) + "ServiceDefinition";
- }
-
- private String simpleServiceName() {
- return grpcClass().getSimpleName().toString().replaceFirst("Grpc$", "");
- }
-
- private TypeElement serviceImplBase(TypeMirror service) {
- ClassName serviceClassName = ClassName.get(MoreTypes.asTypeElement(service));
- ClassName serviceImplBaseName = serviceClassName.nestedClass(simpleServiceName() + "ImplBase");
- return elements.getTypeElement(serviceImplBaseName.toString());
- }
-
- private boolean validateGrpcClass(TypeMirror type, AnnotationValue value) {
- TypeElement serviceImplBase = serviceImplBase(type);
- if (serviceImplBase == null || !types.isSubtype(serviceImplBase.asType(), bindableService())) {
- messager.printMessage(
- Kind.ERROR,
- String.format("%s is not a gRPC service class", type),
- serviceImplementation,
- grpcServiceAnnotation(),
- value);
- return false;
- }
- if (!(types.isSubtype(serviceImplementation.asType(), serviceImplBase.asType()))) {
- messager.printMessage(
- Kind.ERROR,
- String.format(
- "%s must extend %s", serviceImplementation, serviceImplBase.getQualifiedName()),
- serviceImplementation,
- grpcServiceAnnotation(),
- value);
- return false;
- }
- return true;
- }
-
- private TypeMirror bindableService() {
- return elements.getTypeElement(IoGrpc.BINDABLE_SERVICE.toString()).asType();
- }
-
- static final AnnotationValueVisitor<TypeElement, AnnotationValue> GET_TYPE_ELEMENT_FROM_VALUE =
- new SimpleAnnotationValueVisitor7<TypeElement, AnnotationValue>() {
- @Override
- public TypeElement visitType(TypeMirror t, AnnotationValue p) {
- return MoreTypes.asTypeElement(t);
- }
-
- @Override
- protected TypeElement defaultAction(Object o, AnnotationValue p) {
- throw new IllegalArgumentException("Expected " + p + " to be a class");
- }
- };
-}
diff --git a/java/dagger/grpc/server/processor/GrpcServiceModuleGenerator.java b/java/dagger/grpc/server/processor/GrpcServiceModuleGenerator.java
deleted file mode 100644
index bbad143..0000000
--- a/java/dagger/grpc/server/processor/GrpcServiceModuleGenerator.java
+++ /dev/null
@@ -1,90 +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.grpc.server.processor;
-
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static com.squareup.javapoet.WildcardTypeName.subtypeOf;
-import static javax.lang.model.element.Modifier.FINAL;
-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.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.grpc.server.GrpcService;
-import java.util.List;
-
-/**
- * An object that generates the non-proxying service definition module for a {@link
- * GrpcService}-annotated service implementation.
- */
-final class GrpcServiceModuleGenerator extends SourceGenerator {
-
- private static final TypeName LIST_OF_INTERCEPTORS = ParameterizedTypeName.get(
- ClassName.get(List.class), subtypeOf(IoGrpc.SERVER_INTERCEPTOR));
-
- private final GrpcServiceModel grpcServiceModel;
-
- GrpcServiceModuleGenerator(GrpcServiceModel grpcServiceModel) {
- super(grpcServiceModel.packageName());
- this.grpcServiceModel = grpcServiceModel;
- }
-
- @Override
- protected TypeSpec createType() {
- TypeSpec.Builder serviceModule =
- classBuilder(grpcServiceModel.serviceModuleName)
- .addJavadoc(
- "Install this module in the {@link $T @Singleton} server component\n",
- JavaxInject.singleton().type)
- .addJavadoc(
- "or in the subcomponent that implements {@link $T}.\n",
- grpcServiceModel.serviceDefinitionTypeName);
- grpcServiceModel.generatedAnnotation().ifPresent(serviceModule::addAnnotation);
- return serviceModule
- .addAnnotation(Dagger.module())
- .addModifiers(PUBLIC, FINAL)
- .addMethod(provideServiceDefinition())
- .build();
- }
-
- /**
- * Returns the {@link dagger.Provides @Provides} method for the {@link
- * io.grpc.ServerServiceDefinition} for the service.
- */
- private MethodSpec provideServiceDefinition() {
- return methodBuilder("serviceDefinition")
- .addAnnotation(Dagger.provides())
- .addAnnotation(grpcServiceModel.forGrpcService())
- .addModifiers(STATIC)
- .returns(IoGrpc.SERVER_SERVICE_DEFINITION)
- .addParameter(grpcServiceModel.serviceImplementationClassName, "implementation")
- .addParameter(
- ParameterSpec.builder(LIST_OF_INTERCEPTORS, "interceptors")
- .addAnnotation(grpcServiceModel.forGrpcService())
- .build())
- .addStatement(
- "$T serviceDefinition = implementation.bindService()", IoGrpc.SERVER_SERVICE_DEFINITION)
- .addStatement(
- "return $T.intercept(serviceDefinition, interceptors)", IoGrpc.SERVER_INTERCEPTORS)
- .build();
- }
-}
diff --git a/java/dagger/grpc/server/processor/GrpcServiceProcessor.java b/java/dagger/grpc/server/processor/GrpcServiceProcessor.java
deleted file mode 100644
index e361fdb..0000000
--- a/java/dagger/grpc/server/processor/GrpcServiceProcessor.java
+++ /dev/null
@@ -1,95 +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.grpc.server.processor;
-
-import static javax.lang.model.util.ElementFilter.typesIn;
-
-import com.google.auto.common.BasicAnnotationProcessor;
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
-import com.google.googlejavaformat.java.filer.FormattingFiler;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import dagger.grpc.server.GrpcService;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Processor;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic.Kind;
-
-/**
- * Generates code from types annotated with {@link GrpcService @GrpcService}.
- *
- * @see <a href="https://dagger.dev/grpc">https://dagger.dev/grpc</a>
- */
-@AutoService(Processor.class)
-public class GrpcServiceProcessor extends BasicAnnotationProcessor implements ProcessingStep {
-
- @Override
- protected ImmutableList<GrpcServiceProcessor> initSteps() {
- return ImmutableList.of(this);
- }
-
- @Override
- public ImmutableSet<Class<GrpcService>> annotations() {
- return ImmutableSet.of(GrpcService.class);
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latest();
- }
-
- @Override
- public Set<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
- for (TypeElement element : typesIn(elementsByAnnotation.get(GrpcService.class))) {
- try {
- GrpcServiceModel grpcServiceModel = new GrpcServiceModel(processingEnv, element);
- if (grpcServiceModel.validate()) {
- write(new ServiceDefinitionTypeGenerator(grpcServiceModel), element);
- write(new ProxyModuleGenerator(grpcServiceModel), element);
- write(new GrpcServiceModuleGenerator(grpcServiceModel), element);
- write(new UnscopedGrpcServiceModuleGenerator(grpcServiceModel), element);
- }
- } catch (TypeNotPresentException e) {
- deferredElements.add(element);
- }
- }
- return deferredElements.build();
- }
-
- private void write(SourceGenerator grpcServiceTypeWriter, final TypeElement element) {
- JavaFile javaFile = grpcServiceTypeWriter.javaFile();
- ClassName outputClassName = ClassName.get(javaFile.packageName, javaFile.typeSpec.name);
- try {
- javaFile.writeTo(new FormattingFiler(processingEnv.getFiler()));
- } catch (IOException e) {
- processingEnv
- .getMessager()
- .printMessage(
- Kind.ERROR, String.format("Error writing %s: %s", outputClassName, e), element);
- }
- }
-}
diff --git a/java/dagger/grpc/server/processor/ProxyModuleGenerator.java b/java/dagger/grpc/server/processor/ProxyModuleGenerator.java
deleted file mode 100644
index 60aea8e..0000000
--- a/java/dagger/grpc/server/processor/ProxyModuleGenerator.java
+++ /dev/null
@@ -1,180 +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.grpc.server.processor;
-
-import static com.google.auto.common.MoreElements.hasModifiers;
-import static com.google.common.collect.ImmutableList.toImmutableList;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.fieldsIn;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.CodeBlock;
-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.grpc.server.GrpcService;
-import java.util.List;
-import java.util.function.Function;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * An object that generates the proxying service definition module for a {@link
- * GrpcService}-annotated service implementation.
- */
-final class ProxyModuleGenerator extends SourceGenerator {
-
- private final GrpcServiceModel grpcServiceModel;
-
- ProxyModuleGenerator(GrpcServiceModel grpcServiceModel) {
- super(grpcServiceModel.packageName());
- this.grpcServiceModel = grpcServiceModel;
- }
-
- @Override
- protected TypeSpec createType() {
- TypeSpec.Builder proxyModule =
- classBuilder(grpcServiceModel.proxyModuleName)
- .addModifiers(PUBLIC, FINAL)
- .addJavadoc(
- "Install this module in the {@link $T @Singleton} server component.\n",
- JavaxInject.singleton().type);
- grpcServiceModel.generatedAnnotation().ifPresent(proxyModule::addAnnotation);
- return proxyModule
- .addAnnotation(Dagger.module())
- .addMethod(provideServiceDefinitionContribution())
- .addMethod(provideServiceDefinitionFactory())
- .build();
- }
-
- /**
- * Returns the {@link dagger.Provides @Provides} method for the proxying {@link
- * io.grpc.ServerServiceDefinition}.
- */
- private MethodSpec provideServiceDefinitionContribution() {
- MethodSpec.Builder method =
- methodBuilder("serviceDefinition")
- .addAnnotation(Dagger.provides())
- .addAnnotation(Dagger.intoSet())
- .addAnnotation(JavaxInject.singleton())
- .addModifiers(STATIC)
- .returns(IoGrpc.SERVER_SERVICE_DEFINITION)
- .addParameter(
- ParameterSpec.builder(
- Dagger.GrpcServer.SERVICE_DEFINITION_FACTORY, "serviceDefinitionFactory")
- .addAnnotation(grpcServiceModel.forGrpcService())
- .build())
- .addCode(
- "return $T.builder($T.SERVICE_NAME)",
- IoGrpc.SERVER_SERVICE_DEFINITION,
- grpcServiceModel.grpcClass());
- for (CodeBlock methodDescriptor : methodDescriptors()) {
- method.addCode(
- ".addMethod($T.proxyMethod($L, serviceDefinitionFactory))",
- Dagger.GrpcServer.PROXY_SERVER_CALL_HANDLER,
- methodDescriptor);
- }
- method.addCode(".build();");
- return method.build();
- }
-
- /**
- * Returns the {@link io.grpc.MethodDescriptor} references from the class enclosing the service
- * interface.
- *
- * <p>Looks first for public static methods (new in 1.8), and then for public static fields if it
- * finds none.
- */
- private ImmutableList<CodeBlock> methodDescriptors() {
- ImmutableList<CodeBlock> staticMethodCalls =
- findMethodDescriptors(
- methodsIn(grpcServiceModel.grpcClass().getEnclosedElements()),
- ExecutableElement::getReturnType,
- method ->
- CodeBlock.of("$T.$N()", grpcServiceModel.grpcClass(), method.getSimpleName()));
- if (!staticMethodCalls.isEmpty()) {
- return staticMethodCalls;
- }
- return findMethodDescriptors(
- fieldsIn(grpcServiceModel.grpcClass().getEnclosedElements()),
- VariableElement::asType,
- field -> CodeBlock.of("$T.$N", grpcServiceModel.grpcClass(), field.getSimpleName()));
- }
-
- private <E extends Element> ImmutableList<CodeBlock> findMethodDescriptors(
- List<E> elements,
- Function<? super E, TypeMirror> elementType,
- Function<? super E, CodeBlock> elementReference) {
- return elements
- .stream()
- .filter(hasModifiers(PUBLIC, STATIC)::apply)
- .filter(
- method -> {
- TypeName typeName = TypeName.get(elementType.apply(method));
- return typeName instanceof ParameterizedTypeName
- && ((ParameterizedTypeName) typeName).rawType.equals(IoGrpc.METHOD_DESCRIPTOR);
- })
- .map(elementReference)
- .collect(toImmutableList());
- }
-
- /**
- * Returns the {@link dagger.Provides @Provides} method for the {@link
- * dagger.grpc.server.ProxyServerCallHandler.ServiceDefinitionFactory} used by the proxy.
- */
- private MethodSpec provideServiceDefinitionFactory() {
- return methodBuilder("serviceDefinitionFactory")
- .addAnnotation(Dagger.provides())
- .addAnnotation(grpcServiceModel.forGrpcService())
- .addModifiers(STATIC)
- .returns(Dagger.GrpcServer.SERVICE_DEFINITION_FACTORY)
- .addParameter(grpcServiceModel.serviceDefinitionTypeFactoryName, "factory", FINAL)
- .addStatement("return $L", anonymousServiceDefinitionFactory())
- .build();
- }
-
- /**
- * Returns the anonymous inner class that implements the {@link
- * dagger.grpc.server.ProxyServerCallHandler.ServiceDefinitionFactory} used by the proxy.
- */
- private TypeSpec anonymousServiceDefinitionFactory() {
- return anonymousClassBuilder("")
- .addSuperinterface(Dagger.GrpcServer.SERVICE_DEFINITION_FACTORY)
- .addMethod(
- methodBuilder("getServiceDefinition")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(IoGrpc.SERVER_SERVICE_DEFINITION)
- .addParameter(IoGrpc.METADATA, "headers")
- .addStatement(
- "return factory.grpcService(new $T(headers)).$N()",
- Dagger.GrpcServer.GRPC_CALL_METADATA_MODULE,
- grpcServiceModel.subcomponentServiceDefinitionMethodName())
- .build())
- .build();
- }
-}
diff --git a/java/dagger/grpc/server/processor/ServiceDefinitionTypeGenerator.java b/java/dagger/grpc/server/processor/ServiceDefinitionTypeGenerator.java
deleted file mode 100644
index 15e13fb..0000000
--- a/java/dagger/grpc/server/processor/ServiceDefinitionTypeGenerator.java
+++ /dev/null
@@ -1,67 +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.grpc.server.processor;
-
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.interfaceBuilder;
-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.squareup.javapoet.TypeSpec;
-import dagger.grpc.server.GrpcService;
-
-/**
- * An object that generates the component supertype interface for a {@link GrpcService}-annotated
- * service implementation.
- */
-final class ServiceDefinitionTypeGenerator extends SourceGenerator {
-
- private final GrpcServiceModel grpcServiceModel;
-
- ServiceDefinitionTypeGenerator(GrpcServiceModel grpcServiceModel) {
- super(grpcServiceModel.packageName());
- this.grpcServiceModel = grpcServiceModel;
- }
-
- @Override
- protected TypeSpec createType() {
- TypeSpec.Builder type =
- interfaceBuilder(grpcServiceModel.serviceDefinitionTypeName.simpleName())
- .addJavadoc("A component must implement this interface.\n")
- .addModifiers(PUBLIC);
- grpcServiceModel.generatedAnnotation().ifPresent(type::addAnnotation);
- type.addType(
- interfaceBuilder(grpcServiceModel.serviceDefinitionTypeFactoryName.simpleName())
- .addModifiers(PUBLIC, STATIC)
- .addMethod(
- methodBuilder("grpcService")
- .addModifiers(PUBLIC, ABSTRACT)
- .returns(grpcServiceModel.serviceDefinitionTypeName)
- .addParameter(
- Dagger.GrpcServer.GRPC_CALL_METADATA_MODULE, "grpcCallMetadataModule")
- .build())
- .build());
- type.addMethod(
- methodBuilder(grpcServiceModel.subcomponentServiceDefinitionMethodName())
- .addModifiers(PUBLIC, ABSTRACT)
- .returns(IoGrpc.SERVER_SERVICE_DEFINITION)
- .addAnnotation(grpcServiceModel.forGrpcService())
- .build());
- return type.build();
- }
-}
diff --git a/java/dagger/grpc/server/processor/SourceGenerator.java b/java/dagger/grpc/server/processor/SourceGenerator.java
deleted file mode 100644
index 806d6e6..0000000
--- a/java/dagger/grpc/server/processor/SourceGenerator.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.grpc.server.processor;
-
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-
-/**
- * An object that generates one top-level type.
- */
-abstract class SourceGenerator {
-
- private final String packageName;
-
- protected SourceGenerator(String packageName) {
- this.packageName = packageName;
- }
-
- public JavaFile javaFile() {
- return JavaFile.builder(packageName, createType()).build();
- }
-
- /**
- * Creates the type to write.
- */
- protected abstract TypeSpec createType();
-
- /** Class names and annotation specs for types in the {@link dagger} package. */
- protected static final class Dagger {
- private Dagger() {}
-
- static AnnotationSpec binds() {
- return AnnotationSpec.builder(ClassName.get("dagger", "Binds")).build();
- }
-
- static AnnotationSpec intoSet() {
- return AnnotationSpec.builder(ClassName.get("dagger.multibindings", "IntoSet")).build();
- }
-
- static AnnotationSpec provides() {
- return AnnotationSpec.builder(ClassName.get("dagger", "Provides")).build();
- }
-
- /** A {@code @dagger.Module} annotation that includes the given module classes. */
- static AnnotationSpec module(ClassName... includedModules) {
- AnnotationSpec.Builder module = AnnotationSpec.builder(ClassName.get("dagger", "Module"));
- for (ClassName includedModule : includedModules) {
- module.addMember("includes", "$T.class", includedModule);
- }
- return module.build();
- }
-
- /** Class names and annotation specs for types in the {@link dagger.grpc} package. */
- protected static final class GrpcServer {
- private GrpcServer() {}
-
- static final ClassName PROXY_SERVER_CALL_HANDLER =
- ClassName.get("dagger.grpc.server", "ProxyServerCallHandler");
-
- static final ClassName GRPC_CALL_METADATA_MODULE =
- ClassName.get("dagger.grpc.server", "GrpcCallMetadataModule");
-
- static final ClassName SERVICE_DEFINITION_FACTORY =
- PROXY_SERVER_CALL_HANDLER.nestedClass("ServiceDefinitionFactory");
- }
- }
-
- /** Class names and annotation specs for types in the {@link io.grpc} package. */
- protected static final class IoGrpc {
- private IoGrpc() {}
-
- static final ClassName BINDABLE_SERVICE = ClassName.get("io.grpc", "BindableService");
- static final ClassName METADATA = ClassName.get("io.grpc", "Metadata");
- static final ClassName METHOD_DESCRIPTOR = ClassName.get("io.grpc", "MethodDescriptor");
- static final ClassName SERVER_INTERCEPTOR =
- ClassName.get("io.grpc", "ServerInterceptor");
- static final ClassName SERVER_INTERCEPTORS =
- ClassName.get("io.grpc", "ServerInterceptors");
- static final ClassName SERVER_SERVICE_DEFINITION =
- ClassName.get("io.grpc", "ServerServiceDefinition");
- }
-
- /** Class names and annotation specs for types in the {@link javax.inject} package. */
- protected static final class JavaxInject {
- private JavaxInject() {}
-
- static AnnotationSpec inject() {
- return AnnotationSpec.builder(ClassName.get("javax.inject", "Inject")).build();
- }
-
- static AnnotationSpec singleton() {
- return AnnotationSpec.builder(ClassName.get("javax.inject", "Singleton")).build();
- }
- }
-}
diff --git a/java/dagger/grpc/server/processor/UnscopedGrpcServiceModuleGenerator.java b/java/dagger/grpc/server/processor/UnscopedGrpcServiceModuleGenerator.java
deleted file mode 100644
index 339fb0f..0000000
--- a/java/dagger/grpc/server/processor/UnscopedGrpcServiceModuleGenerator.java
+++ /dev/null
@@ -1,110 +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.grpc.server.processor;
-
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-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.squareup.javapoet.ClassName;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.grpc.server.GrpcService;
-
-/**
- * An object that generates the unscoped-proxying service definition module for a {@link
- * GrpcService}-annotated service implementation.
- */
-final class UnscopedGrpcServiceModuleGenerator extends SourceGenerator {
-
- private final GrpcServiceModel grpcServiceModel;
-
- UnscopedGrpcServiceModuleGenerator(GrpcServiceModel grpcServiceModel) {
- super(grpcServiceModel.packageName());
- this.grpcServiceModel = grpcServiceModel;
- }
-
- @Override
- protected TypeSpec createType() {
- ClassName unscopedComponentFactory =
- grpcServiceModel.unscopedServiceModuleName.nestedClass(
- grpcServiceModel.serviceImplementationClassName.simpleName() + "ComponentFactory");
- TypeSpec.Builder unscopedServiceModule =
- classBuilder(grpcServiceModel.unscopedServiceModuleName)
- .addJavadoc(
- "Install this module in the {@link $T @Singleton} server component\n",
- JavaxInject.singleton().type)
- .addJavadoc(
- "if it implements {@link $T}.\n", grpcServiceModel.serviceDefinitionTypeName);
- grpcServiceModel.generatedAnnotation().ifPresent(unscopedServiceModule::addAnnotation);
- return unscopedServiceModule
- .addAnnotation(
- Dagger.module(grpcServiceModel.proxyModuleName, grpcServiceModel.serviceModuleName))
- .addModifiers(PUBLIC, ABSTRACT)
- .addType(unscopedComponentFactory(unscopedComponentFactory.simpleName()))
- .addMethod(bindSubcomponentFactory(unscopedComponentFactory))
- .addMethod(constructorBuilder().addModifiers(PRIVATE).build())
- .build();
- }
-
- /**
- * Returns the class that implements the component factory type by returning the singleton
- * component itself.
- */
- private TypeSpec unscopedComponentFactory(String simpleName) {
- return TypeSpec.classBuilder(simpleName)
- .addModifiers(STATIC, FINAL)
- .addSuperinterface(grpcServiceModel.serviceDefinitionTypeFactoryName)
- .addField(grpcServiceModel.serviceDefinitionTypeName, "component", PRIVATE, FINAL)
- .addMethod(
- MethodSpec.constructorBuilder()
- .addAnnotation(JavaxInject.inject())
- .addParameter(grpcServiceModel.serviceDefinitionTypeName, "component")
- .addStatement("this.component = component")
- .build())
- .addMethod(
- MethodSpec.methodBuilder("grpcService")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(grpcServiceModel.serviceDefinitionTypeName)
- .addParameter(Dagger.GrpcServer.GRPC_CALL_METADATA_MODULE, "grpcCallMetadataModule")
- .addStatement("return component")
- .build())
- .build();
- }
-
- /**
- * Returns the {@link dagger.Binds @Binds} method that binds the component factory type to the
- * {@linkplain #unscopedComponentFactory(String) unscoped component factory implementation class}.
- */
- private MethodSpec bindSubcomponentFactory(ClassName unscopedComponentFactory) {
- return MethodSpec.methodBuilder(
- UPPER_CAMEL.to(
- LOWER_CAMEL, grpcServiceModel.serviceDefinitionTypeFactoryName.simpleName()))
- .addAnnotation(Dagger.binds())
- .addModifiers(ABSTRACT)
- .returns(grpcServiceModel.serviceDefinitionTypeFactoryName)
- .addParameter(unscopedComponentFactory, "factory")
- .build();
- }
-}
diff --git a/java/dagger/internal/AbstractMapFactory.java b/java/dagger/internal/AbstractMapFactory.java
deleted file mode 100644
index 1cf83fa..0000000
--- a/java/dagger/internal/AbstractMapFactory.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;
-
-import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-import static dagger.internal.Preconditions.checkNotNull;
-import static java.util.Collections.unmodifiableMap;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.inject.Provider;
-
-/**
- * An {@code abstract} {@link Factory} implementation used to implement {@link Map} bindings.
- *
- * @param <K> the key type of the map that this provides
- * @param <V> the type that each contributing factory
- * @param <V2> the value type of the map that this provides
- */
-abstract class AbstractMapFactory<K, V, V2> implements Factory<Map<K, V2>> {
- private final Map<K, Provider<V>> contributingMap;
-
- AbstractMapFactory(Map<K, Provider<V>> map) {
- this.contributingMap = unmodifiableMap(map);
- }
-
- /** The map of {@link Provider}s that contribute to this map binding. */
- final Map<K, Provider<V>> contributingMap() {
- return contributingMap;
- }
-
- /** A builder for {@link AbstractMapFactory}. */
- public abstract static class Builder<K, V, V2> {
- final LinkedHashMap<K, Provider<V>> map;
-
- Builder(int size) {
- this.map = newLinkedHashMapWithExpectedSize(size);
- }
-
- // Unfortunately, we cannot return a self-type here because a raw Provider type passed to one of
- // these methods affects the returned type of the method. The first put*() call erases the self
- // type to the "raw" self type, and the second erases the type to the upper bound
- // (AbstractMapFactory.Builder), which doesn't have a build() method.
- //
- // The methods are therefore not declared public so that each subtype will redeclare them and
- // expand their accessibility
-
- /** Associates {@code key} with {@code providerOfValue}. */
- Builder<K, V, V2> put(K key, Provider<V> providerOfValue) {
- map.put(checkNotNull(key, "key"), checkNotNull(providerOfValue, "provider"));
- return this;
- }
-
- Builder<K, V, V2> putAll(Provider<Map<K, V2>> mapOfProviders) {
- if (mapOfProviders instanceof DelegateFactory) {
- @SuppressWarnings("unchecked")
- DelegateFactory<Map<K, V2>> asDelegateFactory = (DelegateFactory) mapOfProviders;
- return putAll(asDelegateFactory.getDelegate());
- }
- @SuppressWarnings("unchecked")
- AbstractMapFactory<K, V, ?> asAbstractMapFactory =
- ((AbstractMapFactory<K, V, ?>) (Provider) mapOfProviders);
- map.putAll(asAbstractMapFactory.contributingMap);
- return this;
- }
- }
-}
diff --git a/java/dagger/internal/Beta.java b/java/dagger/internal/Beta.java
deleted file mode 100644
index 2e97f05..0000000
--- a/java/dagger/internal/Beta.java
+++ /dev/null
@@ -1,34 +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;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-/**
- * Signifies that a public API (public class, method or field) is subject to
- * incompatible changes, or even removal, in a future release. An API bearing
- * this annotation is exempt from any compatibility guarantees made by its
- * containing library. Note that the presence of this annotation implies nothing
- * about the quality or performance of the API in question, only the fact that
- * it is not "API-frozen."
- */
-@Documented
-@Retention(SOURCE)
-public @interface Beta {}
diff --git a/java/dagger/internal/ComponentDefinitionType.java b/java/dagger/internal/ComponentDefinitionType.java
deleted file mode 100644
index 1ab8b13..0000000
--- a/java/dagger/internal/ComponentDefinitionType.java
+++ /dev/null
@@ -1,27 +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 static java.lang.annotation.ElementType.TYPE;
-
-import java.lang.annotation.Target;
-
-/** Specifies the user-defined component that is being implemented by the annotated class. */
-@Target(TYPE)
-public @interface ComponentDefinitionType {
- Class<?> value();
-}
diff --git a/java/dagger/internal/ConfigureInitializationParameters.java b/java/dagger/internal/ConfigureInitializationParameters.java
deleted file mode 100644
index 1ca0fbb..0000000
--- a/java/dagger/internal/ConfigureInitializationParameters.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.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/DaggerCollections.java b/java/dagger/internal/DaggerCollections.java
deleted file mode 100644
index cebca42..0000000
--- a/java/dagger/internal/DaggerCollections.java
+++ /dev/null
@@ -1,89 +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;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Collection utility methods in service of Dagger internal classes. <em>Do not use</em> in client
- * code.
- */
-public final class DaggerCollections {
- /**
- * The maximum value for a signed 32-bit integer that is equal to a power of 2.
- */
- private static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
-
- private DaggerCollections() {}
-
- /**
- * Returns a new list that is pre-sized to {@code size}, or {@link Collections#emptyList()} if
- * empty. The list returned is never intended to grow beyond {@code size}, so adding to a list
- * when the size is 0 is an error.
- */
- public static <T> List<T> presizedList(int size) {
- if (size == 0) {
- return Collections.emptyList();
- }
- return new ArrayList<T>(size);
- }
-
- /**
- * Returns true if at least one pair of items in {@code list} are equals.
- */
- public static boolean hasDuplicates(List<?> list) {
- if (list.size() < 2) {
- return false;
- }
- Set<Object> asSet = new HashSet<Object>(list);
- return list.size() != asSet.size();
- }
-
- /**
- * Creates a {@link HashSet} instance, with a high enough "intial capcity" that it <em>should</em>
- * hold {@code expectedSize} elements without growth.
- */
- static <T> HashSet<T> newHashSetWithExpectedSize(int expectedSize) {
- return new HashSet<T>(calculateInitialCapacity(expectedSize));
- }
-
- /**
- * Creates a {@link LinkedHashMap} instance, with a high enough "initial capacity" that it
- * <em>should</em> hold {@code expectedSize} elements without growth.
- */
- public static <K, V> LinkedHashMap<K, V> newLinkedHashMapWithExpectedSize(int expectedSize) {
- return new LinkedHashMap<K, V>(calculateInitialCapacity(expectedSize));
- }
-
- private static int calculateInitialCapacity(int expectedSize) {
- if (expectedSize < 3) {
- return expectedSize + 1;
- }
- if (expectedSize < MAX_POWER_OF_TWO) {
- // This is the calculation used in JDK8 to resize when a putAll
- // happens; it seems to be the most conservative calculation we
- // can make. 0.75 is the default load factor.
- return (int) (expectedSize / 0.75F + 1.0F);
- }
- return Integer.MAX_VALUE; // any large value
- }
-}
diff --git a/java/dagger/internal/DelegateFactory.java b/java/dagger/internal/DelegateFactory.java
deleted file mode 100644
index 3b4a30f..0000000
--- a/java/dagger/internal/DelegateFactory.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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import javax.inject.Provider;
-
-/**
- * A DelegateFactory that is used to stitch Provider/Lazy indirection based dependency cycles.
- *
- * @since 2.0.1
- */
-public final class DelegateFactory<T> implements Factory<T> {
- private Provider<T> delegate;
-
- @Override
- public T get() {
- if (delegate == null) {
- throw new IllegalStateException();
- }
- return delegate.get();
- }
-
- // TODO(ronshapiro): remove this once we can reasonably expect generated code is no longer using
- // this method
- @Deprecated
- public void setDelegatedProvider(Provider<T> delegate) {
- setDelegate(this, delegate);
- }
-
- /**
- * Sets {@code delegateFactory}'s delegate provider to {@code delegate}.
- *
- * <p>{@code delegateFactory} must be an instance of {@link DelegateFactory}, otherwise this
- * method will throw a {@link ClassCastException}.
- */
- public static <T> void setDelegate(Provider<T> delegateFactory, Provider<T> delegate) {
- checkNotNull(delegate);
- DelegateFactory<T> asDelegateFactory = (DelegateFactory<T>) delegateFactory;
- if (asDelegateFactory.delegate != null) {
- throw new IllegalStateException();
- }
- asDelegateFactory.delegate = delegate;
- }
-
- /**
- * Returns the factory's delegate.
- *
- * @throws NullPointerException if the delegate has not been set
- */
- Provider<T> getDelegate() {
- return checkNotNull(delegate);
- }
-}
-
diff --git a/java/dagger/internal/DoubleCheck.java b/java/dagger/internal/DoubleCheck.java
deleted file mode 100644
index ea07528..0000000
--- a/java/dagger/internal/DoubleCheck.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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import dagger.Lazy;
-import javax.inject.Provider;
-
-/**
- * A {@link Lazy} and {@link Provider} implementation that memoizes the value returned from a
- * delegate using the double-check idiom described in Item 71 of <i>Effective Java 2</i>.
- */
-public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
- private static final Object UNINITIALIZED = new Object();
-
- private volatile Provider<T> provider;
- private volatile Object instance = UNINITIALIZED;
-
- private DoubleCheck(Provider<T> provider) {
- assert provider != null;
- this.provider = provider;
- }
-
- @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
- @Override
- public T get() {
- Object result = instance;
- if (result == UNINITIALIZED) {
- synchronized (this) {
- result = instance;
- if (result == UNINITIALIZED) {
- result = provider.get();
- instance = reentrantCheck(instance, result);
- /* Null out the reference to the provider. We are never going to need it again, so we
- * can make it eligible for GC. */
- provider = null;
- }
- }
- }
- return (T) result;
- }
-
- /**
- * Checks to see if creating the new instance has resulted in a recursive call. If it has, and the
- * new instance is the same as the current instance, return the instance. However, if the new
- * instance differs from the current instance, an {@link IllegalStateException} is thrown.
- */
- public static Object reentrantCheck(Object currentInstance, Object newInstance) {
- boolean isReentrant = !(currentInstance == UNINITIALIZED
- // This check is needed for fastInit's implementation, which uses MemoizedSentinel types.
- || currentInstance instanceof MemoizedSentinel);
-
- if (isReentrant && currentInstance != newInstance) {
- throw new IllegalStateException("Scoped provider was invoked recursively returning "
- + "different results: " + currentInstance + " & " + newInstance + ". This is likely "
- + "due to a circular dependency.");
- }
- return newInstance;
- }
-
- /** Returns a {@link Provider} that caches the value from the given delegate provider. */
- // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> delegate)"
- // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
- public static <P extends Provider<T>, T> Provider<T> provider(P delegate) {
- checkNotNull(delegate);
- if (delegate instanceof DoubleCheck) {
- /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
- * binding, we shouldn't cache the value again. */
- return delegate;
- }
- return new DoubleCheck<T>(delegate);
- }
-
- /** Returns a {@link Lazy} that caches the value from the given provider. */
- // This method is declared this way instead of "<T> Lazy<T> lazy(Provider<T> delegate)"
- // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
- public static <P extends Provider<T>, T> Lazy<T> lazy(P provider) {
- if (provider instanceof Lazy) {
- @SuppressWarnings("unchecked")
- final Lazy<T> lazy = (Lazy<T>) provider;
- // Avoids memoizing a value that is already memoized.
- // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
- // are different types using covariant return on get(). Right now this is used with
- // DoubleCheck<T> exclusively, which is implemented such that P and L are always
- // the same, so it will be fine for that case.
- return lazy;
- }
- return new DoubleCheck<T>(checkNotNull(provider));
- }
-}
diff --git a/java/dagger/internal/Factory.java b/java/dagger/internal/Factory.java
deleted file mode 100644
index 9c03f81..0000000
--- a/java/dagger/internal/Factory.java
+++ /dev/null
@@ -1,36 +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;
-
-import dagger.Provides;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Scope;
-
-/**
- * An {@linkplain Scope unscoped} {@link Provider}. While a {@link Provider} <i>may</i> apply
- * scoping semantics while providing an instance, a factory implementation is guaranteed to exercise
- * the binding logic ({@link Inject} constructors, {@link Provides} methods) upon each call to
- * {@link #get}.
- *
- * <p>Note that while subsequent calls to {@link #get} will create new instances for bindings such
- * as those created by {@link Inject} constructors, a new instance is not guaranteed by all
- * bindings. For example, {@link Provides} methods may be implemented in ways that return the same
- * instance for each call.
- */
-public interface Factory<T> extends Provider<T> {
-}
diff --git a/java/dagger/internal/GenerationOptions.java b/java/dagger/internal/GenerationOptions.java
deleted file mode 100644
index 996cd1d..0000000
--- a/java/dagger/internal/GenerationOptions.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;
-
-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/GwtIncompatible.java b/java/dagger/internal/GwtIncompatible.java
deleted file mode 100644
index f6100a2..0000000
--- a/java/dagger/internal/GwtIncompatible.java
+++ /dev/null
@@ -1,20 +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;
-
-/** Marks an element incompatible with GWT. */
-public @interface GwtIncompatible {}
diff --git a/java/dagger/internal/InstanceFactory.java b/java/dagger/internal/InstanceFactory.java
deleted file mode 100644
index 3156fe8..0000000
--- a/java/dagger/internal/InstanceFactory.java
+++ /dev/null
@@ -1,61 +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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import dagger.Lazy;
-
-/**
- * A {@link Factory} implementation that returns a single instance for all invocations of {@link
- * #get}.
- *
- * <p>Note that while this is a {@link Factory} implementation, and thus unscoped, each call to
- * {@link #get} will always return the same instance. As such, any scoping applied to this factory
- * is redundant and unnecessary. However, using this with {@link DoubleCheck#provider} is valid and
- * may be desired for testing or contractual guarantees.
- */
-public final class InstanceFactory<T> implements Factory<T>, Lazy<T> {
- public static <T> Factory<T> create(T instance) {
- return new InstanceFactory<T>(checkNotNull(instance, "instance cannot be null"));
- }
-
- public static <T> Factory<T> createNullable(T instance) {
- return instance == null
- ? InstanceFactory.<T>nullInstanceFactory()
- : new InstanceFactory<T>(instance);
- }
-
- @SuppressWarnings("unchecked") // bivariant implementation
- private static <T> InstanceFactory<T> nullInstanceFactory() {
- return (InstanceFactory<T>) NULL_INSTANCE_FACTORY;
- }
-
- private static final InstanceFactory<Object> NULL_INSTANCE_FACTORY =
- new InstanceFactory<Object>(null);
-
- private final T instance;
-
- private InstanceFactory(T instance) {
- this.instance = instance;
- }
-
- @Override
- public T get() {
- return instance;
- }
-}
diff --git a/java/dagger/internal/MapBuilder.java b/java/dagger/internal/MapBuilder.java
deleted file mode 100644
index 25e2b5b..0000000
--- a/java/dagger/internal/MapBuilder.java
+++ /dev/null
@@ -1,60 +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;
-
-import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * A fluent builder class that returns a {@link Map}. Used in component implementations where a map
- * must be created in one fluent statement for inlined request fulfillments.
- */
-public final class MapBuilder<K, V> {
- private final Map<K, V> contributions;
-
- private MapBuilder(int size) {
- contributions = newLinkedHashMapWithExpectedSize(size);
- }
-
- /**
- * Creates a new {@link MapBuilder} with {@code size} elements.
- */
- public static <K, V> MapBuilder<K, V> newMapBuilder(int size) {
- return new MapBuilder<>(size);
- }
-
- public MapBuilder<K, V> put(K key, V value) {
- contributions.put(key, value);
- return this;
- }
-
- public MapBuilder<K, V> putAll(Map<K, V> map) {
- contributions.putAll(map);
- return this;
- }
-
- public Map<K, V> build() {
- switch (contributions.size()) {
- case 0:
- return Collections.emptyMap();
- default:
- return Collections.unmodifiableMap(contributions);
- }
- }
-}
diff --git a/java/dagger/internal/MapFactory.java b/java/dagger/internal/MapFactory.java
deleted file mode 100644
index 8eb0783..0000000
--- a/java/dagger/internal/MapFactory.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;
-
-import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-import static java.util.Collections.unmodifiableMap;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.inject.Provider;
-
-/**
- * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
- * {@code Map<K, V>} when calling {@link #get} (as specified by {@link Factory}).
- */
-public final class MapFactory<K, V> extends AbstractMapFactory<K, V, V> {
- private static final Provider<Map<Object, Object>> EMPTY =
- InstanceFactory.create(Collections.emptyMap());
-
- /** Returns a new {@link Builder} */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- /** Returns a factory of an empty map. */
- @SuppressWarnings("unchecked") // safe contravariant cast
- public static <K, V> Provider<Map<K, V>> emptyMapProvider() {
- return (Provider<Map<K, V>>) (Provider) EMPTY;
- }
-
- private MapFactory(Map<K, Provider<V>> map) {
- super(map);
- }
-
- /**
- * Returns a {@code Map<K, V>} whose iteration order is that of the elements given by each of the
- * providers, which are invoked in the order given at creation.
- */
- @Override
- public Map<K, V> get() {
- Map<K, V> result = newLinkedHashMapWithExpectedSize(contributingMap().size());
- for (Entry<K, Provider<V>> entry : contributingMap().entrySet()) {
- result.put(entry.getKey(), entry.getValue().get());
- }
- return unmodifiableMap(result);
- }
-
- /** A builder for {@link MapFactory}. */
- public static final class Builder<K, V> extends AbstractMapFactory.Builder<K, V, V> {
- private Builder(int size) {
- super(size);
- }
-
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- super.put(key, providerOfValue);
- return this;
- }
-
- public Builder<K, V> putAll(Provider<Map<K, V>> mapFactory) {
- super.putAll(mapFactory);
- return this;
- }
-
- /** Returns a new {@link MapProviderFactory}. */
- public MapFactory<K, V> build() {
- return new MapFactory<>(map);
- }
- }
-}
diff --git a/java/dagger/internal/MapProviderFactory.java b/java/dagger/internal/MapProviderFactory.java
deleted file mode 100644
index 1fe4788..0000000
--- a/java/dagger/internal/MapProviderFactory.java
+++ /dev/null
@@ -1,71 +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;
-
-import dagger.Lazy;
-import java.util.Map;
-import javax.inject.Provider;
-
-/**
- * A {@link Factory} implementation used to implement {@link Map} bindings. This factory returns a
- * {@code Map<K, Provider<V>>} when calling {@link #get} (as specified by {@link Factory}).
- */
-public final class MapProviderFactory<K, V> extends AbstractMapFactory<K, V, Provider<V>>
- implements Lazy<Map<K, Provider<V>>> {
-
- /** Returns a new {@link Builder} */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- private MapProviderFactory(Map<K, Provider<V>> contributingMap) {
- super(contributingMap);
- }
-
- /**
- * Returns a {@code Map<K, Provider<V>>} whose iteration order is that of the elements given by
- * each of the providers, which are invoked in the order given at creation.
- */
- @Override
- public Map<K, Provider<V>> get() {
- return contributingMap();
- }
-
- /** A builder for {@link MapProviderFactory}. */
- public static final class Builder<K, V> extends AbstractMapFactory.Builder<K, V, Provider<V>> {
- private Builder(int size) {
- 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, Provider<V>>> mapProviderFactory) {
- super.putAll(mapProviderFactory);
- return this;
- }
-
- /** Returns a new {@link MapProviderFactory}. */
- public MapProviderFactory<K, V> build() {
- return new MapProviderFactory<>(map);
- }
- }
-}
diff --git a/java/dagger/internal/MembersInjectors.java b/java/dagger/internal/MembersInjectors.java
deleted file mode 100644
index aae068c..0000000
--- a/java/dagger/internal/MembersInjectors.java
+++ /dev/null
@@ -1,48 +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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import dagger.MembersInjector;
-import javax.inject.Inject;
-
-/**
- * Basic {@link MembersInjector} implementations used by the framework.
- */
-public final class MembersInjectors {
- /**
- * Returns a {@link MembersInjector} implementation that injects no members
- *
- * <p>Note that there is no verification that the type being injected does not have {@link Inject}
- * members, so care should be taken to ensure appropriate use.
- */
- @SuppressWarnings("unchecked")
- public static <T> MembersInjector<T> noOp() {
- return (MembersInjector<T>) NoOpMembersInjector.INSTANCE;
- }
-
- private static enum NoOpMembersInjector implements MembersInjector<Object> {
- INSTANCE;
-
- @Override public void injectMembers(Object instance) {
- checkNotNull(instance, "Cannot inject members into a null reference");
- }
- }
-
- private MembersInjectors() {}
-}
diff --git a/java/dagger/internal/MemoizedSentinel.java b/java/dagger/internal/MemoizedSentinel.java
deleted file mode 100644
index dd24dcd..0000000
--- a/java/dagger/internal/MemoizedSentinel.java
+++ /dev/null
@@ -1,20 +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;
-
-/** A sentinel used to memoize a scoped binding in a component. */
-public final class MemoizedSentinel {}
diff --git a/java/dagger/internal/MissingBindingFactory.java b/java/dagger/internal/MissingBindingFactory.java
deleted file mode 100644
index 993d150..0000000
--- a/java/dagger/internal/MissingBindingFactory.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;
-
-/**
- * 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
deleted file mode 100644
index 1e658e4..0000000
--- a/java/dagger/internal/ModifiableBinding.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.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
deleted file mode 100644
index 983321e..0000000
--- a/java/dagger/internal/ModifiableModule.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.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
deleted file mode 100644
index 714a353..0000000
--- a/java/dagger/internal/Preconditions.java
+++ /dev/null
@@ -1,100 +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;
-
-/**
- * An adaptation of Guava's {@code com.google.common.base.Preconditions} that is specially tailored
- * to support checks applied in Dagger's generated code.
- */
-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 that an object reference passed as a parameter to the calling method is not null.
- *
- * @param reference an object reference
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing the single {@code %s} placeholder in the template with
- * {@code errorMessageArg}.
- * @param errorMessageArg the argument to be substituted into the message template. Converted to a
- * string using {@link String#valueOf(Object)}, except for {@link Class} objects, which use
- * {@link Class#getCanonicalName()}.
- * @return the non-null reference that was validated
- * @throws NullPointerException if {@code reference} is null
- * @throws IllegalArgumentException if {@code errorMessageTemplate} doesn't contain exactly one
- * "%s"
- */
- public static <T> T checkNotNull(
- T reference, String errorMessageTemplate, Object errorMessageArg) {
- if (reference == null) {
- // Simple implementation of String.format, which is not GWT-compatible
- if (!errorMessageTemplate.contains("%s")) {
- throw new IllegalArgumentException("errorMessageTemplate has no format specifiers");
- }
- if (errorMessageTemplate.indexOf("%s") != errorMessageTemplate.lastIndexOf("%s")) {
- throw new IllegalArgumentException(
- "errorMessageTemplate has more than one format specifier");
- }
- String argString =
- errorMessageArg instanceof Class
- ? ((Class) errorMessageArg).getCanonicalName()
- : String.valueOf(errorMessageArg);
- throw new NullPointerException(errorMessageTemplate.replace("%s", argString));
- }
- return reference;
- }
-
- /**
- * Checks that the component builder field {@code requirement} has been initialized.
- *
- * @throws IllegalStateException if {@code requirement is null}
- */
- public static <T> void checkBuilderRequirement(T requirement, Class<T> clazz) {
- if (requirement == null) {
- throw new IllegalStateException(clazz.getCanonicalName() + " must be set");
- }
- }
-
- private Preconditions() {}
-}
diff --git a/java/dagger/internal/ProviderOfLazy.java b/java/dagger/internal/ProviderOfLazy.java
deleted file mode 100644
index 23b6afd..0000000
--- a/java/dagger/internal/ProviderOfLazy.java
+++ /dev/null
@@ -1,54 +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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import dagger.Lazy;
-import javax.inject.Provider;
-
-/**
- * A {@link Provider} of {@link Lazy} instances that each delegate to a given {@link Provider}.
- */
-public final class ProviderOfLazy<T> implements Provider<Lazy<T>> {
-
- private final Provider<T> provider;
-
- private ProviderOfLazy(Provider<T> provider) {
- assert provider != null;
- this.provider = provider;
- }
-
- /**
- * Returns a new instance of {@link Lazy Lazy<T>}, which calls {@link Provider#get()} at
- * most once on the {@link Provider} held by this object.
- */
- @Override
- public Lazy<T> get() {
- return DoubleCheck.lazy(provider);
- }
-
- /**
- * Creates a new {@link Provider Provider<Lazy<T>>} that decorates the given
- * {@link Provider}.
- *
- * @see #get()
- */
- public static <T> Provider<Lazy<T>> create(Provider<T> provider) {
- return new ProviderOfLazy<T>(checkNotNull(provider));
- }
-}
diff --git a/java/dagger/internal/SetBuilder.java b/java/dagger/internal/SetBuilder.java
deleted file mode 100644
index 41a2fc7..0000000
--- a/java/dagger/internal/SetBuilder.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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A fluent builder class that returns a {@link Set}. Used in component implementations where a set
- * must be created in one fluent statement for inlined request fulfillments.
- */
-public final class SetBuilder<T> {
- private static final String SET_CONTRIBUTIONS_CANNOT_BE_NULL =
- "Set contributions cannot be null";
- private final List<T> contributions;
-
- private SetBuilder(int estimatedSize) {
- contributions = new ArrayList<>(estimatedSize);
- }
-
- /**
- * {@code estimatedSize} is the number of bindings which contribute to the set. They may each
- * provide {@code [0..n)} instances to the set. Because the final size is unknown, {@code
- * contributions} are collected in a list and only hashed in {@link #build()}.
- */
- public static <T> SetBuilder<T> newSetBuilder(int estimatedSize) {
- return new SetBuilder<T>(estimatedSize);
- }
-
- public SetBuilder<T> add(T t) {
- contributions.add(checkNotNull(t, SET_CONTRIBUTIONS_CANNOT_BE_NULL));
- return this;
- }
-
- public SetBuilder<T> addAll(Collection<? extends T> collection) {
- for (T item : collection) {
- checkNotNull(item, SET_CONTRIBUTIONS_CANNOT_BE_NULL);
- }
- contributions.addAll(collection);
- return this;
- }
-
- public Set<T> build() {
- 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/SetFactory.java b/java/dagger/internal/SetFactory.java
deleted file mode 100644
index 349399b..0000000
--- a/java/dagger/internal/SetFactory.java
+++ /dev/null
@@ -1,136 +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;
-
-import static dagger.internal.DaggerCollections.hasDuplicates;
-import static dagger.internal.DaggerCollections.newHashSetWithExpectedSize;
-import static dagger.internal.DaggerCollections.presizedList;
-import static dagger.internal.Preconditions.checkNotNull;
-import static java.util.Collections.emptySet;
-import static java.util.Collections.unmodifiableSet;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import javax.inject.Provider;
-
-/**
- * A {@link Factory} implementation used to implement {@link Set} bindings. This factory always
- * returns a new {@link Set} instance for each call to {@link #get} (as required by {@link Factory})
- * whose elements are populated by subsequent calls to their {@link Provider#get} methods.
- */
-public final class SetFactory<T> implements Factory<Set<T>> {
- private static final Factory<Set<Object>> EMPTY_FACTORY = InstanceFactory.create(emptySet());
-
- @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
- public static <T> Factory<Set<T>> empty() {
- return (Factory) EMPTY_FACTORY;
- }
-
- /**
- * Constructs a new {@link Builder} for a {@link SetFactory} with {@code individualProviderSize}
- * individual {@code Provider<T>} and {@code collectionProviderSize} {@code
- * Provider<Collection<T>>} instances.
- */
- public static <T> Builder<T> builder(int individualProviderSize, int collectionProviderSize) {
- return new Builder<T>(individualProviderSize, collectionProviderSize);
- }
-
- /**
- * A builder to accumulate {@code Provider<T>} and {@code Provider<Collection<T>>} instances.
- * These are only intended to be single-use and from within generated code. Do <em>NOT</em> add
- * providers after calling {@link #build()}.
- */
- public static final class Builder<T> {
- private final List<Provider<T>> individualProviders;
- private final List<Provider<Collection<T>>> collectionProviders;
-
- private Builder(int individualProviderSize, int collectionProviderSize) {
- individualProviders = presizedList(individualProviderSize);
- collectionProviders = presizedList(collectionProviderSize);
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addProvider(Provider<? extends T> individualProvider) {
- assert individualProvider != null : "Codegen error? Null provider";
- // TODO(ronshapiro): Store a List<? extends Provider<T>> and avoid the cast to Provider<T>
- individualProviders.add((Provider<T>) individualProvider);
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addCollectionProvider(
- Provider<? extends Collection<? extends T>> collectionProvider) {
- assert collectionProvider != null : "Codegen error? Null provider";
- collectionProviders.add((Provider<Collection<T>>) collectionProvider);
- return this;
- }
-
- public SetFactory<T> build() {
- assert !hasDuplicates(individualProviders)
- : "Codegen error? Duplicates in the provider list";
- assert !hasDuplicates(collectionProviders)
- : "Codegen error? Duplicates in the provider list";
-
- return new SetFactory<T>(individualProviders, collectionProviders);
- }
- }
-
- private final List<Provider<T>> individualProviders;
- private final List<Provider<Collection<T>>> collectionProviders;
-
- private SetFactory(
- List<Provider<T>> individualProviders, List<Provider<Collection<T>>> collectionProviders) {
- this.individualProviders = individualProviders;
- this.collectionProviders = collectionProviders;
- }
-
- /**
- * Returns a {@link Set} that contains the elements given by each of the providers.
- *
- * @throws NullPointerException if any of the delegate {@link Set} instances or elements therein
- * are {@code null}
- */
- @Override
- public Set<T> get() {
- int size = individualProviders.size();
- // Profiling revealed that this method was a CPU-consuming hotspot in some applications, so
- // these loops were changed to use c-style for. Versus enhanced for-each loops, C-style for is
- // faster for ArrayLists, at least through Java 8.
-
- List<Collection<T>> providedCollections =
- new ArrayList<Collection<T>>(collectionProviders.size());
- for (int i = 0, c = collectionProviders.size(); i < c; i++) {
- Collection<T> providedCollection = collectionProviders.get(i).get();
- size += providedCollection.size();
- providedCollections.add(providedCollection);
- }
-
- Set<T> providedValues = newHashSetWithExpectedSize(size);
- for (int i = 0, c = individualProviders.size(); i < c; i++) {
- providedValues.add(checkNotNull(individualProviders.get(i).get()));
- }
- for (int i = 0, c = providedCollections.size(); i < c; i++) {
- for (T element : providedCollections.get(i)) {
- providedValues.add(checkNotNull(element));
- }
- }
-
- return unmodifiableSet(providedValues);
- }
-}
diff --git a/java/dagger/internal/SingleCheck.java b/java/dagger/internal/SingleCheck.java
deleted file mode 100644
index 4128069..0000000
--- a/java/dagger/internal/SingleCheck.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;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import javax.inject.Provider;
-
-/**
- * A {@link Provider} implementation that memoizes the result of another {@link Provider} using
- * simple lazy initialization, not the double-checked lock pattern.
- */
-public final class SingleCheck<T> implements Provider<T> {
- private static final Object UNINITIALIZED = new Object();
-
- private volatile Provider<T> provider;
- private volatile Object instance = UNINITIALIZED;
-
- private SingleCheck(Provider<T> provider) {
- assert provider != null;
- this.provider = provider;
- }
-
- @SuppressWarnings("unchecked") // cast only happens when result comes from the delegate provider
- @Override
- public T get() {
- Object local = instance;
- if (local == UNINITIALIZED) {
- // provider is volatile and might become null after the check, so retrieve the provider first
- Provider<T> providerReference = provider;
- if (providerReference == null) {
- // The provider was null, so the instance must already be set
- local = instance;
- } else {
- local = providerReference.get();
- instance = local;
-
- // Null out the reference to the provider. We are never going to need it again, so we can
- // make it eligible for GC.
- provider = null;
- }
- }
- return (T) local;
- }
-
- /** Returns a {@link Provider} that caches the value from the given delegate provider. */
- // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> provider)"
- // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
- public static <P extends Provider<T>, T> Provider<T> provider(P provider) {
- // If a scoped @Binds delegates to a scoped binding, don't cache the value again.
- if (provider instanceof SingleCheck || provider instanceof DoubleCheck) {
- return provider;
- }
- return new SingleCheck<T>(checkNotNull(provider));
- }
-}
diff --git a/java/dagger/internal/codegen/AnnotationCreatorGenerator.java b/java/dagger/internal/codegen/AnnotationCreatorGenerator.java
deleted file mode 100644
index 273f552..0000000
--- a/java/dagger/internal/codegen/AnnotationCreatorGenerator.java
+++ /dev/null
@@ -1,167 +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;
-
-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
deleted file mode 100644
index 8d729e2..0000000
--- a/java/dagger/internal/codegen/AnnotationExpression.java
+++ /dev/null
@@ -1,207 +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;
-
-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
deleted file mode 100644
index 282d8ca..0000000
--- a/java/dagger/internal/codegen/AnnotationProtoConverter.java
+++ /dev/null
@@ -1,275 +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.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
deleted file mode 100644
index fc30eaa..0000000
--- a/java/dagger/internal/codegen/AnonymousProviderCreationExpression.java
+++ /dev/null
@@ -1,58 +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;
-
-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
deleted file mode 100644
index bad9636..0000000
--- a/java/dagger/internal/codegen/AnyBindingMethodValidator.java
+++ /dev/null
@@ -1,113 +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;
-
-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/BUILD b/java/dagger/internal/codegen/BUILD
deleted file mode 100644
index 824a72e..0000000
--- a/java/dagger/internal/codegen/BUILD
+++ /dev/null
@@ -1,527 +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 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("//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 = [
- "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],
- deps = CODEGEN_DEPS + [
- ":base",
- ":binding",
- ":binding_graph_validation",
- ":writing",
- ":validation",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/langmodel",
- "@google_bazel_common//third_party/java/incap",
- ],
-)
-
-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 = "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",
- ],
-)
-
-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/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",
- ],
-)
-
-# 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",
- ],
-)
-
-java_plugin(
- name = "component-codegen",
- generates_api = 1,
- output_licenses = ["unencumbered"],
- processor_class = "dagger.internal.codegen.ComponentProcessor",
- tags = [
- "annotation=dagger.Component;" +
- "genclass=${package}.Dagger${outerclasses}${classname}",
- "annotation=dagger.producers.ProductionComponent;" +
- "genclass=${package}.Dagger${outerclasses}${classname}",
- ],
- 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
deleted file mode 100644
index c0f6b71..0000000
--- a/java/dagger/internal/codegen/Binding.java
+++ /dev/null
@@ -1,314 +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;
-
-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
deleted file mode 100644
index c9520cd..0000000
--- a/java/dagger/internal/codegen/BindingDeclaration.java
+++ /dev/null
@@ -1,62 +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;
-
-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
deleted file mode 100644
index d850165..0000000
--- a/java/dagger/internal/codegen/BindingDeclarationFormatter.java
+++ /dev/null
@@ -1,124 +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;
-
-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
deleted file mode 100644
index 0051912..0000000
--- a/java/dagger/internal/codegen/BindingElementValidator.java
+++ /dev/null
@@ -1,383 +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;
-
-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
deleted file mode 100644
index 65200f7..0000000
--- a/java/dagger/internal/codegen/BindingExpression.java
+++ /dev/null
@@ -1,111 +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;
-
-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
deleted file mode 100644
index 564b412..0000000
--- a/java/dagger/internal/codegen/BindingFactory.java
+++ /dev/null
@@ -1,508 +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;
-
-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
deleted file mode 100644
index 2f548b2..0000000
--- a/java/dagger/internal/codegen/BindingGraph.java
+++ /dev/null
@@ -1,232 +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;
-
-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
deleted file mode 100644
index a2cc799..0000000
--- a/java/dagger/internal/codegen/BindingGraphConverter.java
+++ /dev/null
@@ -1,239 +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.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
deleted file mode 100644
index d96da8a..0000000
--- a/java/dagger/internal/codegen/BindingGraphFactory.java
+++ /dev/null
@@ -1,1061 +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;
-
-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
deleted file mode 100644
index e2c3812..0000000
--- a/java/dagger/internal/codegen/BindingGraphPlugins.java
+++ /dev/null
@@ -1,77 +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 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
deleted file mode 100644
index 129647f..0000000
--- a/java/dagger/internal/codegen/BindingGraphStatisticsCollector.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.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
deleted file mode 100644
index 63e1fa2..0000000
--- a/java/dagger/internal/codegen/BindingGraphValidationModule.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;
-
-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
deleted file mode 100644
index df17b15..0000000
--- a/java/dagger/internal/codegen/BindingGraphValidator.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;
-
-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
deleted file mode 100644
index e6c4f8e..0000000
--- a/java/dagger/internal/codegen/BindingMethodProcessingStep.java
+++ /dev/null
@@ -1,60 +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;
-
-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
deleted file mode 100644
index 21c05cc..0000000
--- a/java/dagger/internal/codegen/BindingMethodValidator.java
+++ /dev/null
@@ -1,303 +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;
-
-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
deleted file mode 100644
index 28a272d..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index a7da092..0000000
--- a/java/dagger/internal/codegen/BindingNode.java
+++ /dev/null
@@ -1,137 +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.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
deleted file mode 100644
index 27067aa..0000000
--- a/java/dagger/internal/codegen/BindingRequest.java
+++ /dev/null
@@ -1,125 +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 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
deleted file mode 100644
index 37109c7..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 9249c8e..0000000
--- a/java/dagger/internal/codegen/BindsInstanceElementValidator.java
+++ /dev/null
@@ -1,38 +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;
-
-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
deleted file mode 100644
index 1a491c7..0000000
--- a/java/dagger/internal/codegen/BindsInstanceMethodValidator.java
+++ /dev/null
@@ -1,84 +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;
-
-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
deleted file mode 100644
index b2dc8d8..0000000
--- a/java/dagger/internal/codegen/BindsInstanceParameterValidator.java
+++ /dev/null
@@ -1,74 +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;
-
-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
deleted file mode 100644
index 4c222a9..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index e198c3a..0000000
--- a/java/dagger/internal/codegen/BindsMethodValidator.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;
-
-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
deleted file mode 100644
index e1c9d73..0000000
--- a/java/dagger/internal/codegen/BindsOptionalOfMethodValidator.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;
-
-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
deleted file mode 100644
index acecc9e..0000000
--- a/java/dagger/internal/codegen/BindsTypeChecker.java
+++ /dev/null
@@ -1,109 +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;
-
-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
deleted file mode 100644
index a5e0219..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 66ce3ef..0000000
--- a/java/dagger/internal/codegen/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;
-
-/** 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
deleted file mode 100644
index bc3cbf8..0000000
--- a/java/dagger/internal/codegen/CompilerOptions.java
+++ /dev/null
@@ -1,119 +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;
-
-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
deleted file mode 100644
index a8f2ece..0000000
--- a/java/dagger/internal/codegen/ComponentAnnotation.java
+++ /dev/null
@@ -1,323 +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.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
deleted file mode 100644
index 37cf1e8..0000000
--- a/java/dagger/internal/codegen/ComponentBindingExpressions.java
+++ /dev/null
@@ -1,713 +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;
-
-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
deleted file mode 100644
index 31bbfab..0000000
--- a/java/dagger/internal/codegen/ComponentCreatorAnnotation.java
+++ /dev/null
@@ -1,150 +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.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
deleted file mode 100644
index f6ec7a2..0000000
--- a/java/dagger/internal/codegen/ComponentCreatorDescriptor.java
+++ /dev/null
@@ -1,222 +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;
-
-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
deleted file mode 100644
index a5eb680..0000000
--- a/java/dagger/internal/codegen/ComponentCreatorImplementation.java
+++ /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.
- */
-
-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
deleted file mode 100644
index 4f06b90..0000000
--- a/java/dagger/internal/codegen/ComponentCreatorImplementationFactory.java
+++ /dev/null
@@ -1,589 +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;
-
-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
deleted file mode 100644
index dc203de..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c55dadd..0000000
--- a/java/dagger/internal/codegen/ComponentCreatorValidator.java
+++ /dev/null
@@ -1,390 +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;
-
-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
deleted file mode 100644
index 769cc4c..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 7d87eac..0000000
--- a/java/dagger/internal/codegen/ComponentDescriptorFactory.java
+++ /dev/null
@@ -1,268 +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;
-
-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
deleted file mode 100644
index 8f85b3a..0000000
--- a/java/dagger/internal/codegen/ComponentDescriptorValidator.java
+++ /dev/null
@@ -1,484 +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.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
deleted file mode 100644
index 330ec2d..0000000
--- a/java/dagger/internal/codegen/ComponentGenerator.java
+++ /dev/null
@@ -1,71 +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;
-
-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
deleted file mode 100644
index d1e5333..0000000
--- a/java/dagger/internal/codegen/ComponentHierarchyValidator.java
+++ /dev/null
@@ -1,268 +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;
-
-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
deleted file mode 100644
index 47857ca..0000000
--- a/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
+++ /dev/null
@@ -1,299 +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;
-
-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 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.
- *
- * <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 {@link BindingGraph} 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 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 ComponentDescriptorFactory componentDescriptorFactory;
-
- @Inject
- ComponentHjarProcessingStep(
- SourceVersion sourceVersion,
- DaggerElements elements,
- DaggerTypes types,
- Filer filer,
- Messager messager,
- ComponentValidator componentValidator,
- ComponentDescriptorFactory componentDescriptorFactory) {
- super(MoreElements::asType);
- this.sourceVersion = sourceVersion;
- this.elements = elements;
- this.types = types;
- this.filer = filer;
- this.messager = messager;
- this.componentValidator = componentValidator;
- this.componentDescriptorFactory = componentDescriptorFactory;
- }
-
- @Override
- public Set<Class<? extends Annotation>> annotations() {
- return rootComponentAnnotations();
- }
-
- @Override
- protected void process(
- 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 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 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
deleted file mode 100644
index 340da14..0000000
--- a/java/dagger/internal/codegen/ComponentImplementation.java
+++ /dev/null
@@ -1,929 +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;
-
-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
deleted file mode 100644
index 7579ac9..0000000
--- a/java/dagger/internal/codegen/ComponentImplementationBuilder.java
+++ /dev/null
@@ -1,826 +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;
-
-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
deleted file mode 100644
index 9578ece..0000000
--- a/java/dagger/internal/codegen/ComponentImplementationFactory.java
+++ /dev/null
@@ -1,162 +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;
-
-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
deleted file mode 100644
index e98d595..0000000
--- a/java/dagger/internal/codegen/ComponentInstanceBindingExpression.java
+++ /dev/null
@@ -1,42 +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;
-
-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
deleted file mode 100644
index 8e5b9ba..0000000
--- a/java/dagger/internal/codegen/ComponentKind.java
+++ /dev/null
@@ -1,170 +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;
-
-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
deleted file mode 100644
index 7e7bbd8..0000000
--- a/java/dagger/internal/codegen/ComponentMethodBindingExpression.java
+++ /dev/null
@@ -1,90 +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;
-
-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
deleted file mode 100644
index 3a31ec7..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 645c94f..0000000
--- a/java/dagger/internal/codegen/ComponentProcessingStep.java
+++ /dev/null
@@ -1,278 +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;
-
-import static com.google.common.collect.Sets.union;
-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.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;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A {@link ProcessingStep} that is responsible for dealing with a component or production component
- * as part of the {@link ComponentProcessor}.
- */
-final class ComponentProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final ComponentValidator componentValidator;
- private final ComponentCreatorValidator creatorValidator;
- private final ComponentDescriptorValidator componentDescriptorValidator;
- 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(
- Messager messager,
- ComponentValidator componentValidator,
- ComponentCreatorValidator creatorValidator,
- ComponentDescriptorValidator componentDescriptorValidator,
- ComponentDescriptorFactory componentDescriptorFactory,
- BindingGraphFactory bindingGraphFactory,
- SourceFileGenerator<BindingGraph> componentGenerator,
- BindingGraphConverter bindingGraphConverter,
- BindingGraphValidator bindingGraphValidator,
- CompilerOptions compilerOptions) {
- super(MoreElements::asType);
- this.messager = messager;
- this.componentValidator = componentValidator;
- this.creatorValidator = creatorValidator;
- this.componentDescriptorValidator = componentDescriptorValidator;
- this.componentDescriptorFactory = componentDescriptorFactory;
- this.bindingGraphFactory = bindingGraphFactory;
- this.componentGenerator = componentGenerator;
- this.bindingGraphConverter = bindingGraphConverter;
- this.bindingGraphValidator = bindingGraphValidator;
- this.compilerOptions = compilerOptions;
- }
-
- @Override
- public Set<Class<? extends Annotation>> annotations() {
- return union(allComponentAnnotations(), allCreatorAnnotations());
- }
-
- @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())) {
- processRootComponent(element);
- }
- if (!disjoint(annotations, subcomponentAnnotations())) {
- processSubcomponent(element);
- }
- }
-
- private void processRootComponent(TypeElement component) {
- if (!isRootComponentValid(component)) {
- return;
- }
- ComponentDescriptor componentDescriptor =
- componentDescriptorFactory.rootComponentDescriptor(component);
- if (!isValid(componentDescriptor)) {
- return;
- }
- if (!isFullBindingGraphValid(componentDescriptor)) {
- return;
- }
- BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor, false);
- if (isValid(bindingGraph)) {
- generateComponent(bindingGraph);
- }
- }
-
- private void processSubcomponent(TypeElement 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.
- 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);
- }
-
- 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 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);
- }
-
- 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 isValid(fullBindingGraph);
- }
-
- private boolean isValid(ComponentDescriptor componentDescriptor) {
- ValidationReport<TypeElement> componentDescriptorReport =
- componentDescriptorValidator.validate(componentDescriptor);
- 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
deleted file mode 100644
index 541a4ab..0000000
--- a/java/dagger/internal/codegen/ComponentProcessor.java
+++ /dev/null
@@ -1,203 +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;
-
-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.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.spi.BindingGraphPlugin;
-import java.util.Arrays;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.SourceVersion;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/**
- * The annotation processor responsible for generating the classes that drive the Dagger 2.0
- * implementation.
- *
- * <p>TODO(gak): give this some better documentation
- */
-@IncrementalAnnotationProcessor(DYNAMIC)
-@AutoService(Processor.class)
-public class ComponentProcessor extends BasicAnnotationProcessor {
- private final Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins;
-
- @Inject InjectBindingRegistry injectBindingRegistry;
- @Inject SourceFileGenerator<ProvisionBinding> factoryGenerator;
- @Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
- @Inject ImmutableList<ProcessingStep> processingSteps;
- @Inject BindingGraphPlugins bindingGraphPlugins;
- @Inject CompilerOptions compilerOptions;
- @Inject DaggerStatisticsCollector statisticsCollector;
- @Inject Set<ClearableCache> clearableCaches;
-
- public ComponentProcessor() {
- this.testingPlugins = Optional.empty();
- }
-
- private ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins) {
- this.testingPlugins = Optional.of(ImmutableSet.copyOf(testingPlugins));
- }
-
- /**
- * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
- * them from a {@link java.util.ServiceLoader}.
- */
- @VisibleForTesting
- public static ComponentProcessor forTesting(BindingGraphPlugin... testingPlugins) {
- return forTesting(Arrays.asList(testingPlugins));
- }
-
- /**
- * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
- * them from a {@link java.util.ServiceLoader}.
- */
- @VisibleForTesting
- public static ComponentProcessor forTesting(Iterable<BindingGraphPlugin> testingPlugins) {
- return new ComponentProcessor(testingPlugins);
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latestSupported();
- }
-
- @Override
- public Set<String> getSupportedOptions() {
- 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.builder()
- .processingEnvironmentModule(new ProcessingEnvironmentModule(processingEnv))
- .testingPlugins(testingPlugins)
- .build()
- .inject(this);
-
- statisticsCollector.processingStarted();
- bindingGraphPlugins.initializePlugins();
- return Iterables.transform(
- processingSteps,
- step -> new DaggerStatisticsCollectingProcessingStep(step, statisticsCollector));
- }
-
- @Singleton
- @Component(
- modules = {
- BindingGraphValidationModule.class,
- BindingMethodValidatorsModule.class,
- InjectBindingRegistryModule.class,
- ProcessingEnvironmentModule.class,
- ProcessingRoundCacheModule.class,
- ProcessingStepsModule.class,
- SourceFileGeneratorsModule.class,
- SpiModule.class,
- SystemComponentsModule.class,
- TopLevelImplementationComponent.InstallationModule.class,
- })
- interface ProcessorComponent {
- void inject(ComponentProcessor processor);
-
- static Builder builder() {
- return DaggerComponentProcessor_ProcessorComponent.builder();
- }
-
- @CanIgnoreReturnValue
- @Component.Builder
- interface Builder {
- Builder processingEnvironmentModule(ProcessingEnvironmentModule module);
-
- @BindsInstance
- Builder testingPlugins(
- @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins);
-
- @CheckReturnValue ProcessorComponent build();
- }
- }
-
- @Module
- interface ProcessingStepsModule {
- @Provides
- static ImmutableList<ProcessingStep> processingSteps(
- MapKeyProcessingStep mapKeyProcessingStep,
- InjectProcessingStep injectProcessingStep,
- MonitoringModuleProcessingStep monitoringModuleProcessingStep,
- MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep,
- BindsInstanceProcessingStep bindsInstanceProcessingStep,
- ModuleProcessingStep moduleProcessingStep,
- ComponentProcessingStep componentProcessingStep,
- ComponentHjarProcessingStep componentHjarProcessingStep,
- BindingMethodProcessingStep bindingMethodProcessingStep,
- CompilerOptions compilerOptions) {
- return ImmutableList.of(
- mapKeyProcessingStep,
- injectProcessingStep,
- 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);
- }
- }
-
- @Override
- protected void postRound(RoundEnvironment roundEnv) {
- statisticsCollector.roundFinished();
- if (roundEnv.processingOver()) {
- statisticsCollector.processingStopped();
- } else {
- try {
- injectBindingRegistry.generateSourcesForRequiredBindings(
- factoryGenerator, membersInjectorGenerator);
- } catch (SourceFileGenerationException e) {
- e.printMessageTo(processingEnv.getMessager());
- }
- }
- clearableCaches.forEach(ClearableCache::clearCache);
- }
-}
diff --git a/java/dagger/internal/codegen/ComponentProvisionBindingExpression.java b/java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
deleted file mode 100644
index b8c6049..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 3bed5da..0000000
--- a/java/dagger/internal/codegen/ComponentRequirement.java
+++ /dev/null
@@ -1,247 +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;
-
-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
deleted file mode 100644
index d6aa053..0000000
--- a/java/dagger/internal/codegen/ComponentRequirementBindingExpression.java
+++ /dev/null
@@ -1,46 +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;
-
-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
deleted file mode 100644
index b25c01b..0000000
--- a/java/dagger/internal/codegen/ComponentRequirementExpression.java
+++ /dev/null
@@ -1,54 +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;
-
-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
deleted file mode 100644
index 4ab58c9..0000000
--- a/java/dagger/internal/codegen/ComponentRequirementExpressions.java
+++ /dev/null
@@ -1,334 +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;
-
-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
deleted file mode 100644
index cc1efd2..0000000
--- a/java/dagger/internal/codegen/ComponentTreeTraverser.java
+++ /dev/null
@@ -1,180 +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;
-
-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
deleted file mode 100644
index 7739915..0000000
--- a/java/dagger/internal/codegen/ComponentValidator.java
+++ /dev/null
@@ -1,522 +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;
-
-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
deleted file mode 100644
index a9bba29..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 0958bc8..0000000
--- a/java/dagger/internal/codegen/ContributionBinding.java
+++ /dev/null
@@ -1,209 +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;
-
-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
deleted file mode 100644
index 66b5289..0000000
--- a/java/dagger/internal/codegen/ContributionType.java
+++ /dev/null
@@ -1,67 +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;
-
-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
deleted file mode 100644
index c78d60d..0000000
--- a/java/dagger/internal/codegen/CurrentImplementationSubcomponent.java
+++ /dev/null
@@ -1,58 +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 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
deleted file mode 100644
index dda6c11..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 5a685ef..0000000
--- a/java/dagger/internal/codegen/DaggerKythePlugin.java
+++ /dev/null
@@ -1,194 +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;
-
-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
deleted file mode 100644
index 790ec76..0000000
--- a/java/dagger/internal/codegen/DaggerStatistics.java
+++ /dev/null
@@ -1,90 +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 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
deleted file mode 100644
index 51f6fc3..0000000
--- a/java/dagger/internal/codegen/DaggerStatisticsCollectingProcessingStep.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.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
deleted file mode 100644
index e14fbb7..0000000
--- a/java/dagger/internal/codegen/DaggerStatisticsCollector.java
+++ /dev/null
@@ -1,94 +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.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
deleted file mode 100644
index 66f41d1..0000000
--- a/java/dagger/internal/codegen/DaggerStatisticsRecorder.java
+++ /dev/null
@@ -1,23 +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;
-
-/** 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
deleted file mode 100644
index 50d17a6..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c41cf2c..0000000
--- a/java/dagger/internal/codegen/DeferredModifiableBindingExpression.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;
-
-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
deleted file mode 100644
index 8cdf6d1..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 67991de..0000000
--- a/java/dagger/internal/codegen/DelegateDeclaration.java
+++ /dev/null
@@ -1,91 +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;
-
-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
deleted file mode 100644
index 7524cdf..0000000
--- a/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java
+++ /dev/null
@@ -1,56 +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;
-
-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
deleted file mode 100644
index d5d4b62..0000000
--- a/java/dagger/internal/codegen/DependencyCycleValidator.java
+++ /dev/null
@@ -1,319 +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.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
deleted file mode 100644
index 64b0845..0000000
--- a/java/dagger/internal/codegen/DependencyEdgeImpl.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;
-
-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
deleted file mode 100644
index b42f9c4..0000000
--- a/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java
+++ /dev/null
@@ -1,97 +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;
-
-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
deleted file mode 100644
index 8532481..0000000
--- a/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.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;
-
-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
deleted file mode 100644
index 3ad12e2..0000000
--- a/java/dagger/internal/codegen/DependencyRequestFactory.java
+++ /dev/null
@@ -1,237 +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;
-
-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
deleted file mode 100644
index 25becaf..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 1a99818..0000000
--- a/java/dagger/internal/codegen/DependencyRequestValidator.java
+++ /dev/null
@@ -1,97 +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 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
deleted file mode 100644
index 21f2d32..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index e611d22..0000000
--- a/java/dagger/internal/codegen/DependsOnProductionExecutorValidator.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;
-
-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
deleted file mode 100644
index 4f2f622..0000000
--- a/java/dagger/internal/codegen/DerivedFromFrameworkInstanceBindingExpression.java
+++ /dev/null
@@ -1,82 +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.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
deleted file mode 100644
index 45e99a8..0000000
--- a/java/dagger/internal/codegen/DeserializedComponentImplementationBuilder.java
+++ /dev/null
@@ -1,256 +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.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
deleted file mode 100644
index 8502ecb..0000000
--- a/java/dagger/internal/codegen/DiagnosticFormatting.java
+++ /dev/null
@@ -1,71 +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;
-
-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
deleted file mode 100644
index f657cee..0000000
--- a/java/dagger/internal/codegen/DiagnosticReporterFactory.java
+++ /dev/null
@@ -1,519 +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.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
deleted file mode 100644
index 3eed45f..0000000
--- a/java/dagger/internal/codegen/DuplicateBindingsValidator.java
+++ /dev/null
@@ -1,332 +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.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
deleted file mode 100644
index 40d7606..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 4195e1a..0000000
--- a/java/dagger/internal/codegen/ErrorMessages.java
+++ /dev/null
@@ -1,356 +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;
-
-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
deleted file mode 100644
index d367bc5..0000000
--- a/java/dagger/internal/codegen/FactoryGenerator.java
+++ /dev/null
@@ -1,290 +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;
-
-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
deleted file mode 100644
index 9ff254e..0000000
--- a/java/dagger/internal/codegen/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;
-
-/** 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
deleted file mode 100644
index 53d4f9a..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 4a1deda..0000000
--- a/java/dagger/internal/codegen/ForwardingCompilerOptions.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.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
deleted file mode 100644
index feea7a0..0000000
--- a/java/dagger/internal/codegen/FrameworkDependency.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;
-
-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
deleted file mode 100644
index de2ada0..0000000
--- a/java/dagger/internal/codegen/FrameworkField.java
+++ /dev/null
@@ -1,130 +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;
-
-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
deleted file mode 100644
index a3de083..0000000
--- a/java/dagger/internal/codegen/FrameworkFieldInitializer.java
+++ /dev/null
@@ -1,217 +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;
-
-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
deleted file mode 100644
index 6f62d66..0000000
--- a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
+++ /dev/null
@@ -1,88 +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;
-
-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
deleted file mode 100644
index 4c45630..0000000
--- a/java/dagger/internal/codegen/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;
-
-/** 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
deleted file mode 100644
index f4e3779..0000000
--- a/java/dagger/internal/codegen/FrameworkType.java
+++ /dev/null
@@ -1,222 +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;
-
-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
deleted file mode 100644
index 7746692..0000000
--- a/java/dagger/internal/codegen/FrameworkTypeMapper.java
+++ /dev/null
@@ -1,85 +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;
-
-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
deleted file mode 100644
index 19d2eda..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 1b14a7e..0000000
--- a/java/dagger/internal/codegen/GenerationCompilerOptions.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;
-
-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
deleted file mode 100644
index aa3c461..0000000
--- a/java/dagger/internal/codegen/GenerationOptionsModule.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;
-
-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
deleted file mode 100644
index 34d8f6d..0000000
--- a/java/dagger/internal/codegen/GwtCompatibility.java
+++ /dev/null
@@ -1,56 +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;
-
-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
deleted file mode 100644
index 5c36322..0000000
--- a/java/dagger/internal/codegen/HjarSourceFileGenerator.java
+++ /dev/null
@@ -1,125 +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;
-
-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
deleted file mode 100644
index 69b107c..0000000
--- a/java/dagger/internal/codegen/ImmediateFutureBindingExpression.java
+++ /dev/null
@@ -1,74 +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.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
deleted file mode 100644
index 19c4d19..0000000
--- a/java/dagger/internal/codegen/InaccessibleMapKeyProxyGenerator.java
+++ /dev/null
@@ -1,72 +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.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
deleted file mode 100644
index d649e46..0000000
--- a/java/dagger/internal/codegen/IncompatiblyScopedBindingsValidator.java
+++ /dev/null
@@ -1,142 +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 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
deleted file mode 100644
index 2840d75..0000000
--- a/java/dagger/internal/codegen/InjectBindingRegistry.java
+++ /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.
- */
-
-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
deleted file mode 100644
index 45dc391..0000000
--- a/java/dagger/internal/codegen/InjectBindingRegistryImpl.java
+++ /dev/null
@@ -1,340 +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;
-
-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
deleted file mode 100644
index 4563362..0000000
--- a/java/dagger/internal/codegen/InjectBindingRegistryModule.java
+++ /dev/null
@@ -1,26 +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 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
deleted file mode 100644
index 183d162..0000000
--- a/java/dagger/internal/codegen/InjectBindingValidator.java
+++ /dev/null
@@ -1,59 +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 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
deleted file mode 100644
index be8c975..0000000
--- a/java/dagger/internal/codegen/InjectProcessingStep.java
+++ /dev/null
@@ -1,76 +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;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import java.lang.annotation.Annotation;
-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.VariableElement;
-import javax.lang.model.util.ElementKindVisitor8;
-
-/**
- * An annotation processor for generating Dagger implementation code based on the {@link Inject}
- * annotation.
- */
-// TODO(gak): add some error handling for bad source files
-final class InjectProcessingStep extends TypeCheckingProcessingStep<Element> {
- private final ElementVisitor<Void, Void> visitor;
-
- @Inject
- InjectProcessingStep(InjectBindingRegistry injectBindingRegistry) {
- super(e -> e);
- this.visitor =
- new ElementKindVisitor8<Void, Void>() {
- @Override
- public Void visitExecutableAsConstructor(
- ExecutableElement constructorElement, Void aVoid) {
- injectBindingRegistry.tryRegisterConstructor(constructorElement);
- return null;
- }
-
- @Override
- public Void visitVariableAsField(VariableElement fieldElement, Void aVoid) {
- injectBindingRegistry.tryRegisterMembersInjectedType(
- MoreElements.asType(fieldElement.getEnclosingElement()));
- return null;
- }
-
- @Override
- public Void visitExecutableAsMethod(ExecutableElement methodElement, Void aVoid) {
- injectBindingRegistry.tryRegisterMembersInjectedType(
- MoreElements.asType(methodElement.getEnclosingElement()));
- return null;
- }
- };
- }
-
- @Override
- public Set<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Inject.class);
- }
-
- @Override
- protected void process(
- Element injectElement, ImmutableSet<Class<? extends Annotation>> annotations) {
- injectElement.accept(visitor, null);
- }
-}
diff --git a/java/dagger/internal/codegen/InjectValidator.java b/java/dagger/internal/codegen/InjectValidator.java
deleted file mode 100644
index d3c4ce8..0000000
--- a/java/dagger/internal/codegen/InjectValidator.java
+++ /dev/null
@@ -1,332 +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;
-
-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
deleted file mode 100644
index 521ad43..0000000
--- a/java/dagger/internal/codegen/InjectionAnnotations.java
+++ /dev/null
@@ -1,68 +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;
-
-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
deleted file mode 100644
index 2785b18..0000000
--- a/java/dagger/internal/codegen/InjectionMethod.java
+++ /dev/null
@@ -1,210 +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.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
deleted file mode 100644
index d61aaa5..0000000
--- a/java/dagger/internal/codegen/InjectionMethods.java
+++ /dev/null
@@ -1,544 +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;
-
-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
deleted file mode 100644
index 2d2e8cb..0000000
--- a/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
+++ /dev/null
@@ -1,63 +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;
-
-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
deleted file mode 100644
index d09f91d..0000000
--- a/java/dagger/internal/codegen/InjectionSiteFactory.java
+++ /dev/null
@@ -1,161 +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;
-
-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
deleted file mode 100644
index 74c4366..0000000
--- a/java/dagger/internal/codegen/InnerSwitchingProviders.java
+++ /dev/null
@@ -1,106 +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.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
deleted file mode 100644
index c9b26d7..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index bc5b66e..0000000
--- a/java/dagger/internal/codegen/JavacPluginModule.java
+++ /dev/null
@@ -1,184 +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;
-
-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
deleted file mode 100644
index b6ac27f..0000000
--- a/java/dagger/internal/codegen/KeyFactory.java
+++ /dev/null
@@ -1,469 +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;
-
-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
deleted file mode 100644
index 407f208..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 670fda7..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 526c493..0000000
--- a/java/dagger/internal/codegen/MapBindingExpression.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;
-
-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
deleted file mode 100644
index 187b792..0000000
--- a/java/dagger/internal/codegen/MapFactoryCreationExpression.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;
-
-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
deleted file mode 100644
index ce27877..0000000
--- a/java/dagger/internal/codegen/MapKeyAccessibility.java
+++ /dev/null
@@ -1,78 +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;
-
-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
deleted file mode 100644
index 19975a7..0000000
--- a/java/dagger/internal/codegen/MapKeyProcessingStep.java
+++ /dev/null
@@ -1,88 +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;
-
-import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
-import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.MapKey;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-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.type.DeclaredType;
-
-/**
- * The annotation processor responsible for validating the mapKey annotation and auto-generate
- * implementation of annotations marked with {@link MapKey @MapKey} where necessary.
- */
-public class MapKeyProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final DaggerTypes types;
- private final MapKeyValidator mapKeyValidator;
- private final AnnotationCreatorGenerator annotationCreatorGenerator;
- private final UnwrappedMapKeyGenerator unwrappedMapKeyGenerator;
-
- @Inject
- MapKeyProcessingStep(
- Messager messager,
- DaggerTypes types,
- MapKeyValidator mapKeyValidator,
- AnnotationCreatorGenerator annotationCreatorGenerator,
- UnwrappedMapKeyGenerator unwrappedMapKeyGenerator) {
- super(MoreElements::asType);
- this.messager = messager;
- this.types = types;
- this.mapKeyValidator = mapKeyValidator;
- this.annotationCreatorGenerator = annotationCreatorGenerator;
- this.unwrappedMapKeyGenerator = unwrappedMapKeyGenerator;
- }
-
- @Override
- public Set<Class<? extends Annotation>> annotations() {
- return ImmutableSet.<Class<? extends Annotation>>of(MapKey.class);
- }
-
- @Override
- protected void process(
- TypeElement mapKeyAnnotationType, ImmutableSet<Class<? extends Annotation>> annotations) {
- ValidationReport<Element> mapKeyReport = mapKeyValidator.validate(mapKeyAnnotationType);
- mapKeyReport.printMessagesTo(messager);
-
- if (mapKeyReport.isClean()) {
- MapKey mapkey = mapKeyAnnotationType.getAnnotation(MapKey.class);
- if (!mapkey.unwrapValue()) {
- annotationCreatorGenerator.generate(mapKeyAnnotationType, messager);
- } else if (unwrappedValueKind(mapKeyAnnotationType).equals(ANNOTATION_TYPE)) {
- unwrappedMapKeyGenerator.generate(mapKeyAnnotationType, messager);
- }
- }
- }
-
- private ElementKind unwrappedValueKind(TypeElement mapKeyAnnotationType) {
- DeclaredType unwrappedMapKeyType =
- getUnwrappedMapKeyType(MoreTypes.asDeclared(mapKeyAnnotationType.asType()), types);
- return unwrappedMapKeyType.asElement().getKind();
- }
-}
diff --git a/java/dagger/internal/codegen/MapKeyValidator.java b/java/dagger/internal/codegen/MapKeyValidator.java
deleted file mode 100644
index f2568ef..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index d8da6af..0000000
--- a/java/dagger/internal/codegen/MapKeys.java
+++ /dev/null
@@ -1,225 +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;
-
-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
deleted file mode 100644
index 346d271..0000000
--- a/java/dagger/internal/codegen/MapMultibindingValidator.java
+++ /dev/null
@@ -1,199 +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.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
deleted file mode 100644
index 73ecdbf..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c42c7c9..0000000
--- a/java/dagger/internal/codegen/MemberSelect.java
+++ /dev/null
@@ -1,274 +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;
-
-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
deleted file mode 100644
index 4918fa1..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index e9a8ffc..0000000
--- a/java/dagger/internal/codegen/MembersInjectionBindingExpression.java
+++ /dev/null
@@ -1,71 +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;
-
-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
deleted file mode 100644
index 1e04669..0000000
--- a/java/dagger/internal/codegen/MembersInjectionMethods.java
+++ /dev/null
@@ -1,126 +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;
-
-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
deleted file mode 100644
index 036315e..0000000
--- a/java/dagger/internal/codegen/MembersInjectionValidator.java
+++ /dev/null
@@ -1,149 +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.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
deleted file mode 100644
index 4360af7..0000000
--- a/java/dagger/internal/codegen/MembersInjectorGenerator.java
+++ /dev/null
@@ -1,204 +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;
-
-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
deleted file mode 100644
index 8e863e5..0000000
--- a/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java
+++ /dev/null
@@ -1,65 +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;
-
-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
deleted file mode 100644
index 2120e80..0000000
--- a/java/dagger/internal/codegen/MethodBindingExpression.java
+++ /dev/null
@@ -1,323 +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.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
deleted file mode 100644
index ef5c9c5..0000000
--- a/java/dagger/internal/codegen/MethodSignature.java
+++ /dev/null
@@ -1,55 +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;
-
-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
deleted file mode 100644
index 012d5b0..0000000
--- a/java/dagger/internal/codegen/MethodSignatureFormatter.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;
-
-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
deleted file mode 100644
index 610d052..0000000
--- a/java/dagger/internal/codegen/MissingBindingExpression.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;
-
-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
deleted file mode 100644
index f39361d..0000000
--- a/java/dagger/internal/codegen/MissingBindingValidator.java
+++ /dev/null
@@ -1,131 +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.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
deleted file mode 100644
index 412acae..0000000
--- a/java/dagger/internal/codegen/ModifiableAbstractMethodBindingExpression.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;
-
-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
deleted file mode 100644
index 76bcb8b..0000000
--- a/java/dagger/internal/codegen/ModifiableBindingExpressions.java
+++ /dev/null
@@ -1,526 +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;
-
-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
deleted file mode 100644
index ead708d..0000000
--- a/java/dagger/internal/codegen/ModifiableBindingMethods.java
+++ /dev/null
@@ -1,133 +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.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
deleted file mode 100644
index 7e43ec1..0000000
--- a/java/dagger/internal/codegen/ModifiableBindingType.java
+++ /dev/null
@@ -1,99 +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 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
deleted file mode 100644
index 907466b..0000000
--- a/java/dagger/internal/codegen/ModifiableConcreteMethodBindingExpression.java
+++ /dev/null
@@ -1,99 +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;
-
-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
deleted file mode 100644
index 27dd071..0000000
--- a/java/dagger/internal/codegen/ModuleAnnotation.java
+++ /dev/null
@@ -1,135 +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.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
deleted file mode 100644
index 5f0d687..0000000
--- a/java/dagger/internal/codegen/ModuleConstructorProxyGenerator.java
+++ /dev/null
@@ -1,85 +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.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
deleted file mode 100644
index ac7a4b7..0000000
--- a/java/dagger/internal/codegen/ModuleDescriptor.java
+++ /dev/null
@@ -1,225 +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;
-
-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
deleted file mode 100644
index 161b47b..0000000
--- a/java/dagger/internal/codegen/ModuleGenerator.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;
-
-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
deleted file mode 100644
index c93d8ce..0000000
--- a/java/dagger/internal/codegen/ModuleKind.java
+++ /dev/null
@@ -1,107 +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;
-
-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
deleted file mode 100644
index 27cd531..0000000
--- a/java/dagger/internal/codegen/ModuleProcessingStep.java
+++ /dev/null
@@ -1,125 +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;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-import static javax.lang.model.util.ElementFilter.typesIn;
-
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.DelegateDeclaration.Factory;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.lang.annotation.Annotation;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A {@link ProcessingStep} that validates module classes and generates factories for binding
- * methods.
- */
-final class ModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final ModuleValidator moduleValidator;
- private final BindingFactory bindingFactory;
- private final SourceFileGenerator<ProvisionBinding> factoryGenerator;
- private final SourceFileGenerator<ProductionBinding> producerFactoryGenerator;
- private final SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator;
- private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator;
- private final DelegateDeclaration.Factory delegateDeclarationFactory;
- private final Set<TypeElement> processedModuleElements = Sets.newLinkedHashSet();
-
- @Inject
- ModuleProcessingStep(
- Messager messager,
- ModuleValidator moduleValidator,
- BindingFactory bindingFactory,
- SourceFileGenerator<ProvisionBinding> factoryGenerator,
- SourceFileGenerator<ProductionBinding> producerFactoryGenerator,
- @ModuleGenerator SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator,
- InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator,
- Factory delegateDeclarationFactory) {
- super(MoreElements::asType);
- this.messager = messager;
- this.moduleValidator = moduleValidator;
- this.bindingFactory = bindingFactory;
- this.factoryGenerator = factoryGenerator;
- this.producerFactoryGenerator = producerFactoryGenerator;
- this.moduleConstructorProxyGenerator = moduleConstructorProxyGenerator;
- this.inaccessibleMapKeyProxyGenerator = inaccessibleMapKeyProxyGenerator;
- this.delegateDeclarationFactory = delegateDeclarationFactory;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Module.class, ProducerModule.class);
- }
-
- @Override
- public ImmutableSet<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- List<TypeElement> modules = typesIn(elementsByAnnotation.values());
- moduleValidator.addKnownModules(modules);
- return super.process(elementsByAnnotation);
- }
-
- @Override
- protected void process(
- TypeElement module, ImmutableSet<Class<? extends Annotation>> annotations) {
- if (processedModuleElements.contains(module)) {
- return;
- }
- ValidationReport<TypeElement> report = moduleValidator.validate(module);
- report.printMessagesTo(messager);
- if (report.isClean()) {
- 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 <B extends ContributionBinding> void generate(
- SourceFileGenerator<B> generator, B binding) {
- generator.generate(binding, messager);
- inaccessibleMapKeyProxyGenerator.generate(binding, messager);
- }
-
- private ContributionBinding bindsMethodBinding(TypeElement module, ExecutableElement method) {
- return bindingFactory.unresolvedDelegateBinding(
- delegateDeclarationFactory.create(method, module));
- }
-}
diff --git a/java/dagger/internal/codegen/ModuleProxies.java b/java/dagger/internal/codegen/ModuleProxies.java
deleted file mode 100644
index 6426e69..0000000
--- a/java/dagger/internal/codegen/ModuleProxies.java
+++ /dev/null
@@ -1,81 +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 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
deleted file mode 100644
index 094bf34..0000000
--- a/java/dagger/internal/codegen/ModuleValidator.java
+++ /dev/null
@@ -1,644 +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;
-
-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
deleted file mode 100644
index 1738fe9..0000000
--- a/java/dagger/internal/codegen/MonitoringModuleGenerator.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;
-
-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
deleted file mode 100644
index 55ae579..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 92825a0..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 84a4d94..0000000
--- a/java/dagger/internal/codegen/MoreAnnotationValues.java
+++ /dev/null
@@ -1,75 +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;
-
-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
deleted file mode 100644
index b478704..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 2bb0a7e..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c3724dc..0000000
--- a/java/dagger/internal/codegen/MultibindingDeclaration.java
+++ /dev/null
@@ -1,118 +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;
-
-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
deleted file mode 100644
index f0523eb..0000000
--- a/java/dagger/internal/codegen/MultibindingExpression.java
+++ /dev/null
@@ -1,95 +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 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
deleted file mode 100644
index abe161a..0000000
--- a/java/dagger/internal/codegen/MultibindingFactoryCreationExpression.java
+++ /dev/null
@@ -1,95 +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.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
deleted file mode 100644
index bc97d30..0000000
--- a/java/dagger/internal/codegen/MultibindsMethodValidator.java
+++ /dev/null
@@ -1,103 +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;
-
-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
deleted file mode 100644
index 1452c3f..0000000
--- a/java/dagger/internal/codegen/NullableBindingValidator.java
+++ /dev/null
@@ -1,82 +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 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
deleted file mode 100644
index b26ab91..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index dbb0e37..0000000
--- a/java/dagger/internal/codegen/OptionalBindingExpression.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;
-
-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
deleted file mode 100644
index 51c9939..0000000
--- a/java/dagger/internal/codegen/OptionalFactories.java
+++ /dev/null
@@ -1,439 +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;
-
-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
deleted file mode 100644
index ba9e25f..0000000
--- a/java/dagger/internal/codegen/OptionalFactoryInstanceCreationExpression.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;
-
-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
deleted file mode 100644
index 0fdbf68..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 1021c35..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 2d2b583..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 5d4ba18..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c30e67a..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 482c123..0000000
--- a/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
+++ /dev/null
@@ -1,77 +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;
-
-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
deleted file mode 100644
index cf2475d..0000000
--- a/java/dagger/internal/codegen/ProcessingEnvironmentCompilerOptions.java
+++ /dev/null
@@ -1,484 +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.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
deleted file mode 100644
index 1730574..0000000
--- a/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
+++ /dev/null
@@ -1,89 +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.common.base.Preconditions.checkNotNull;
-
-import com.google.googlejavaformat.java.filer.FormattingFiler;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Reusable;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.util.Types;
-
-/** Bindings that depend on the {@link ProcessingEnvironment}. */
-@Module
-final class ProcessingEnvironmentModule {
-
- private final ProcessingEnvironment processingEnvironment;
-
- ProcessingEnvironmentModule(ProcessingEnvironment processingEnvironment) {
- this.processingEnvironment = checkNotNull(processingEnvironment);
- }
-
- @Provides
- @ProcessingOptions
- Map<String, String> processingOptions() {
- return processingEnvironment.getOptions();
- }
-
- @Provides
- Messager messager() {
- return processingEnvironment.getMessager();
- }
-
- @Provides
- Filer filer(CompilerOptions compilerOptions) {
- if (compilerOptions.headerCompilation() || !compilerOptions.formatGeneratedSource()) {
- return processingEnvironment.getFiler();
- } else {
- return new FormattingFiler(processingEnvironment.getFiler());
- }
- }
-
- @Provides
- Types types() {
- return processingEnvironment.getTypeUtils();
- }
-
- @Provides
- SourceVersion sourceVersion() {
- return processingEnvironment.getSourceVersion();
- }
-
- @Provides
- DaggerElements daggerElements() {
- return new DaggerElements(processingEnvironment);
- }
-
- @Provides
- @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
deleted file mode 100644
index 105452a..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index b56cc30..0000000
--- a/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
+++ /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.
- */
-
-package dagger.internal.codegen;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.IntoSet;
-
-/**
- * Binding contributions to a set of {@link ClearableCache}s that will be cleared at the end of each
- * processing round.
- */
-@Module
-interface ProcessingRoundCacheModule {
- @Binds
- @IntoSet
- ClearableCache moduleDescriptorFactory(ModuleDescriptor.Factory cache);
-
- @Binds
- @IntoSet
- ClearableCache bindingGraphFactory(BindingGraphFactory cache);
-
- @Binds
- @IntoSet
- ClearableCache componentImplementationFactory(ComponentImplementationFactory cache);
-}
diff --git a/java/dagger/internal/codegen/ProducerCreationExpression.java b/java/dagger/internal/codegen/ProducerCreationExpression.java
deleted file mode 100644
index 1dd7a1c..0000000
--- a/java/dagger/internal/codegen/ProducerCreationExpression.java
+++ /dev/null
@@ -1,48 +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;
-
-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
deleted file mode 100644
index 87b5a4a..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 3f2bef4..0000000
--- a/java/dagger/internal/codegen/ProducerFactoryGenerator.java
+++ /dev/null
@@ -1,553 +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;
-
-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
deleted file mode 100644
index aca9756..0000000
--- a/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
+++ /dev/null
@@ -1,62 +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;
-
-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
deleted file mode 100644
index 18818d5..0000000
--- a/java/dagger/internal/codegen/ProducerNodeInstanceBindingExpression.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;
-
-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
deleted file mode 100644
index bf45948..0000000
--- a/java/dagger/internal/codegen/ProducesMethodValidator.java
+++ /dev/null
@@ -1,133 +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;
-
-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
deleted file mode 100644
index a22f21c..0000000
--- a/java/dagger/internal/codegen/ProductionBinding.java
+++ /dev/null
@@ -1,146 +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;
-
-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
deleted file mode 100644
index 60166de..0000000
--- a/java/dagger/internal/codegen/ProviderInstanceBindingExpression.java
+++ /dev/null
@@ -1,41 +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 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
deleted file mode 100644
index 01e71ae..0000000
--- a/java/dagger/internal/codegen/ProvidesMethodValidator.java
+++ /dev/null
@@ -1,78 +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;
-
-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
deleted file mode 100644
index 306cb13..0000000
--- a/java/dagger/internal/codegen/ProvisionBinding.java
+++ /dev/null
@@ -1,135 +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;
-
-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
deleted file mode 100644
index 2fb1a0e..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 6eb92ac..0000000
--- a/java/dagger/internal/codegen/PrunedConcreteMethodBindingExpression.java
+++ /dev/null
@@ -1,79 +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 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
deleted file mode 100644
index aa17f5e..0000000
--- a/java/dagger/internal/codegen/RequestKinds.java
+++ /dev/null
@@ -1,203 +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;
-
-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
deleted file mode 100644
index 814995a..0000000
--- a/java/dagger/internal/codegen/ResolvedBindings.java
+++ /dev/null
@@ -1,264 +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;
-
-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
deleted file mode 100644
index 252f712..0000000
--- a/java/dagger/internal/codegen/Scopes.java
+++ /dev/null
@@ -1,84 +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;
-
-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
deleted file mode 100644
index 5efb85f..0000000
--- a/java/dagger/internal/codegen/SetBindingExpression.java
+++ /dev/null
@@ -1,183 +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;
-
-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
deleted file mode 100644
index 9712091..0000000
--- a/java/dagger/internal/codegen/SetFactoryCreationExpression.java
+++ /dev/null
@@ -1,103 +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;
-
-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
deleted file mode 100644
index e4fa584..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 505c8ea..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 909d7ae..0000000
--- a/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
+++ /dev/null
@@ -1,34 +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;
-
-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
deleted file mode 100644
index 805ac7b..0000000
--- a/java/dagger/internal/codegen/SimpleMethodBindingExpression.java
+++ /dev/null
@@ -1,191 +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;
-
-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
deleted file mode 100644
index 7f043db..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 07c1c68..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 7dddc2f..0000000
--- a/java/dagger/internal/codegen/SourceFileGenerator.java
+++ /dev/null
@@ -1,124 +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;
-
-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
deleted file mode 100644
index c32262a..0000000
--- a/java/dagger/internal/codegen/SourceFileGeneratorsModule.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;
-
-import dagger.Module;
-import dagger.Provides;
-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(
- 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;
- }
- }
-
- @Module
- class ProvisionModule extends GeneratorModule<ProvisionBinding, FactoryGenerator> {}
-
- @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> generator(
- ModuleConstructorProxyGenerator 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
deleted file mode 100644
index fd93d0d..0000000
--- a/java/dagger/internal/codegen/SourceFiles.java
+++ /dev/null
@@ -1,348 +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;
-
-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
deleted file mode 100644
index a8f13e1..0000000
--- a/java/dagger/internal/codegen/SpiModule.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;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
-import dagger.spi.BindingGraphPlugin;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.util.Optional;
-import java.util.ServiceLoader;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-
-/** Contains the bindings for {@link BindingGraphValidator} from external SPI providers. */
-@Module
-abstract class SpiModule {
- private SpiModule() {}
-
- @Provides
- @Singleton
- static ImmutableSet<BindingGraphPlugin> externalPlugins(
- @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins) {
- return testingPlugins.orElseGet(
- () ->
- ImmutableSet.copyOf(
- ServiceLoader.load(
- BindingGraphPlugin.class, BindingGraphValidator.class.getClassLoader())));
- }
-
- @Qualifier
- @Retention(RUNTIME)
- @Target({FIELD, PARAMETER, METHOD})
- @interface TestingPlugins {}
-}
diff --git a/java/dagger/internal/codegen/SubcomponentCreatorBindingEdgeImpl.java b/java/dagger/internal/codegen/SubcomponentCreatorBindingEdgeImpl.java
deleted file mode 100644
index c97024e..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index b415d3f..0000000
--- a/java/dagger/internal/codegen/SubcomponentCreatorBindingExpression.java
+++ /dev/null
@@ -1,39 +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;
-
-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
deleted file mode 100644
index 5677857..0000000
--- a/java/dagger/internal/codegen/SubcomponentDeclaration.java
+++ /dev/null
@@ -1,86 +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;
-
-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
deleted file mode 100644
index 0c6a006..0000000
--- a/java/dagger/internal/codegen/SubcomponentFactoryMethodValidator.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;
-
-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
deleted file mode 100644
index f2ffd83..0000000
--- a/java/dagger/internal/codegen/SubcomponentNames.java
+++ /dev/null
@@ -1,182 +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;
-
-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
deleted file mode 100644
index 29633d9..0000000
--- a/java/dagger/internal/codegen/SwitchingProviders.java
+++ /dev/null
@@ -1,227 +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.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
deleted file mode 100644
index 3f59b24..0000000
--- a/java/dagger/internal/codegen/SystemComponentsModule.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;
-
-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
deleted file mode 100644
index 4f456f2..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 306c05d..0000000
--- a/java/dagger/internal/codegen/TopLevelImplementationComponent.java
+++ /dev/null
@@ -1,41 +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 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
deleted file mode 100644
index 00769b2..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index c703bd8..0000000
--- a/java/dagger/internal/codegen/TypeProtoConverter.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.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
deleted file mode 100644
index 11c48b3..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 2b7b02c..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index 1869b7c..0000000
--- a/java/dagger/internal/codegen/Util.java
+++ /dev/null
@@ -1,102 +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;
-
-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
deleted file mode 100644
index f6a4b3f..0000000
--- a/java/dagger/internal/codegen/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;
-
-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
deleted file mode 100644
index d7c3252..0000000
--- a/java/dagger/internal/codegen/ValidationReport.java
+++ /dev/null
@@ -1,288 +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;
-
-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
deleted file mode 100644
index 5d19dc1..0000000
--- a/java/dagger/internal/codegen/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;
-
-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/bootstrap_compiler_deploy.jar b/java/dagger/internal/codegen/bootstrap_compiler_deploy.jar
deleted file mode 100644
index ad9761d..0000000
--- a/java/dagger/internal/codegen/bootstrap_compiler_deploy.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/internal/codegen/dagger_statistics.proto b/java/dagger/internal/codegen/dagger_statistics.proto
deleted file mode 100644
index 273e472..0000000
--- a/java/dagger/internal/codegen/dagger_statistics.proto
+++ /dev/null
@@ -1,25 +0,0 @@
-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/javapoet/AnnotationSpecs.java b/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
deleted file mode 100644
index cc0d7de..0000000
--- a/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
+++ /dev/null
@@ -1,51 +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.javapoet;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-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,
- UNCHECKED,
- ;
-
- @Override
- public String toString() {
- return Ascii.toLowerCase(name());
- }
- }
-
- /** Creates an {@link AnnotationSpec} for {@link SuppressWarnings}. */
- public static AnnotationSpec suppressWarnings(Suppression first, Suppression... rest) {
- checkNotNull(first);
- Arrays.stream(rest).forEach(Preconditions::checkNotNull);
- AnnotationSpec.Builder builder = AnnotationSpec.builder(SuppressWarnings.class);
- Lists.asList(first, rest).forEach(suppression -> builder.addMember("value", "$S", suppression));
- return builder.build();
- }
-
- private AnnotationSpecs() {}
-}
diff --git a/java/dagger/internal/codegen/javapoet/BUILD b/java/dagger/internal/codegen/javapoet/BUILD
deleted file mode 100644
index f829d49..0000000
--- a/java/dagger/internal/codegen/javapoet/BUILD
+++ /dev/null
@@ -1,34 +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
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "javapoet",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen:bootstrap_compiler_plugin"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/langmodel",
- "//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",
- ],
-)
diff --git a/java/dagger/internal/codegen/javapoet/CodeBlocks.java b/java/dagger/internal/codegen/javapoet/CodeBlocks.java
deleted file mode 100644
index 3e9f75d..0000000
--- a/java/dagger/internal/codegen/javapoet/CodeBlocks.java
+++ /dev/null
@@ -1,158 +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.javapoet;
-
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
-import static java.util.stream.StreamSupport.stream;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.google.auto.common.MoreElements;
-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.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import java.util.stream.Collector;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/** Convenience methods for creating {@link CodeBlock}s. */
-public final class CodeBlocks {
- /**
- * Joins {@link CodeBlock} instances in a manner suitable for use as method parameters (or
- * arguments).
- */
- public static Collector<CodeBlock, ?, CodeBlock> toParametersCodeBlock() {
- // TODO(ronshapiro,jakew): consider adding zero-width spaces to help line breaking when the
- // formatter is off. If not, inline this
- return CodeBlock.joining(", ");
- }
-
- /** Concatenates {@link CodeBlock} instances separated by newlines for readability. */
- public static Collector<CodeBlock, ?, CodeBlock> toConcatenatedCodeBlock() {
- return CodeBlock.joining("\n", "", "\n");
- }
-
- /** Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. */
- public static CodeBlock makeParametersCodeBlock(Iterable<CodeBlock> codeBlocks) {
- return stream(codeBlocks.spliterator(), false).collect(toParametersCodeBlock());
- }
-
- /**
- * Returns a comma-separated {@link CodeBlock} using the name of every parameter in {@code
- * parameters}.
- */
- public static CodeBlock parameterNames(Iterable<ParameterSpec> parameters) {
- // TODO(ronshapiro): Add DaggerStreams.stream(Iterable)
- return stream(parameters.spliterator(), false)
- .map(p -> CodeBlock.of("$N", p))
- .collect(toParametersCodeBlock());
- }
-
- /**
- * Returns one unified {@link CodeBlock} which joins each item in {@code codeBlocks} with a
- * newline.
- */
- public static CodeBlock concat(Iterable<CodeBlock> codeBlocks) {
- return stream(codeBlocks.spliterator(), false).collect(toConcatenatedCodeBlock());
- }
-
- /** Adds an annotation to a method. */
- public static void addAnnotation(MethodSpec.Builder method, DeclaredType nullableType) {
- method.addAnnotation(ClassName.get(MoreTypes.asTypeElement(nullableType)));
- }
-
- /**
- * Returns an anonymous {@link javax.inject.Provider} class with the single {@link
- * javax.inject.Provider#get()} method that returns the given {@code expression}.
- */
- public static CodeBlock anonymousProvider(Expression expression) {
- // More of a precondition check that the type Provider is parameterized with is a DeclaredType
- DeclaredType type = MoreTypes.asDeclared(expression.type());
- return anonymousProvider(
- TypeName.get(type), CodeBlock.of("return $L;", expression.codeBlock()));
- }
-
- /**
- * Returns an anonymous {@link javax.inject.Provider} class with the single {@link
- * javax.inject.Provider#get()} method implemented by {@code body}.
- */
- public static CodeBlock anonymousProvider(TypeName providedType, CodeBlock body) {
- return CodeBlock.of(
- "$L",
- anonymousClassBuilder("")
- .superclass(providerOf(providedType))
- .addMethod(
- methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(providedType)
- .addCode(body)
- .build())
- .build());
- }
-
- /** Returns {@code expression} cast to a type. */
- public static CodeBlock cast(CodeBlock expression, Class<?> castTo) {
- return CodeBlock.of("($T) $L", castTo, expression);
- }
-
- public static CodeBlock type(TypeMirror type) {
- return CodeBlock.of("$T", type);
- }
-
- public static CodeBlock stringLiteral(String toWrap) {
- return CodeBlock.of("$S", toWrap);
- }
-
- /** Returns a javadoc {@literal @link} tag that poins to the given {@link ExecutableElement}. */
- public static CodeBlock javadocLinkTo(ExecutableElement executableElement) {
- CodeBlock.Builder builder =
- CodeBlock.builder()
- .add(
- "{@link $T#",
- rawTypeName(
- ClassName.get(MoreElements.asType(executableElement.getEnclosingElement()))));
- switch (executableElement.getKind()) {
- case METHOD:
- builder.add("$L", executableElement.getSimpleName());
- break;
- case CONSTRUCTOR:
- builder.add("$L", executableElement.getEnclosingElement().getSimpleName());
- break;
- case STATIC_INIT:
- case INSTANCE_INIT:
- throw new IllegalArgumentException(
- "cannot create a javadoc link to an initializer: " + executableElement);
- default:
- throw new AssertionError(executableElement.toString());
- }
- builder.add("(");
- builder.add(
- executableElement.getParameters().stream()
- .map(parameter -> CodeBlock.of("$T", rawTypeName(TypeName.get(parameter.asType()))))
- .collect(toParametersCodeBlock()));
- return builder.add(")}").build();
- }
-
- private CodeBlocks() {}
-}
diff --git a/java/dagger/internal/codegen/javapoet/Expression.java b/java/dagger/internal/codegen/javapoet/Expression.java
deleted file mode 100644
index b79c55c..0000000
--- a/java/dagger/internal/codegen/javapoet/Expression.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.javapoet;
-
-import com.google.auto.common.MoreTypes;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Encapsulates a {@link CodeBlock} for an <a
- * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html">expression</a> and the
- * {@link TypeMirror} that it represents from the perspective of the compiler. Consider the
- * following example:
- *
- * <pre><code>
- * {@literal @SuppressWarnings("rawtypes")}
- * private Provider fooImplProvider = DoubleCheck.provider(FooImpl_Factory.create());
- * </code></pre>
- *
- * <p>An {@code Expression} for {@code fooImplProvider.get()} would have a {@link #type()} of {@code
- * java.lang.Object} and not {@code FooImpl}.
- */
-public final class Expression {
- private final TypeMirror type;
- private final CodeBlock codeBlock;
-
- private Expression(TypeMirror type, CodeBlock codeBlock) {
- this.type = type;
- this.codeBlock = codeBlock;
- }
-
- /** Creates a new {@link Expression} with a {@link TypeMirror} and {@link CodeBlock}. */
- public static Expression create(TypeMirror type, CodeBlock expression) {
- return new Expression(type, expression);
- }
-
- /**
- * Creates a new {@link Expression} with a {@link TypeMirror}, {@linkplain CodeBlock#of(String,
- * Object[]) format, and arguments}.
- */
- public static Expression create(TypeMirror type, String format, Object... args) {
- return create(type, CodeBlock.of(format, args));
- }
-
- /** Returns a new expression that casts the current expression to {@code newType}. */
- // TODO(ronshapiro): consider overloads that take a Types and Elements and only cast if necessary,
- // or just embedding a Types/Elements instance in an Expression.
- public Expression castTo(TypeMirror newType) {
- return create(newType, "($T) $L", newType, codeBlock);
- }
-
- /**
- * Returns a new expression that {@link #castTo(TypeMirror)} casts the current expression to its
- * boxed type if this expression has a primitive type.
- */
- public Expression box(DaggerTypes types) {
- return type.getKind().isPrimitive()
- ? castTo(types.boxedClass(MoreTypes.asPrimitiveType(type)).asType())
- : this;
- }
-
- /** The {@link TypeMirror type} to which the expression evaluates. */
- public TypeMirror type() {
- return type;
- }
-
- /** The code of the expression. */
- public CodeBlock codeBlock() {
- return codeBlock;
- }
-
- @Override
- public String toString() {
- return String.format("[%s] %s", type, codeBlock);
- }
-}
diff --git a/java/dagger/internal/codegen/javapoet/TypeNames.java b/java/dagger/internal/codegen/javapoet/TypeNames.java
deleted file mode 100644
index 9301dbc..0000000
--- a/java/dagger/internal/codegen/javapoet/TypeNames.java
+++ /dev/null
@@ -1,149 +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.javapoet;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
-import dagger.MembersInjector;
-import dagger.internal.DoubleCheck;
-import dagger.internal.Factory;
-import dagger.internal.InstanceFactory;
-import dagger.internal.MapFactory;
-import dagger.internal.MapProviderFactory;
-import dagger.internal.MembersInjectors;
-import dagger.internal.ProviderOfLazy;
-import dagger.internal.SetFactory;
-import dagger.internal.SingleCheck;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.AbstractProducer;
-import dagger.producers.internal.DependencyMethodProducer;
-import dagger.producers.internal.MapOfProducedProducer;
-import dagger.producers.internal.MapOfProducerProducer;
-import dagger.producers.internal.MapProducer;
-import dagger.producers.internal.Producers;
-import dagger.producers.internal.SetOfProducedProducer;
-import dagger.producers.internal.SetProducer;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.List;
-import java.util.Set;
-import javax.inject.Provider;
-
-/** Common names and convenience methods for JavaPoet {@link TypeName} usage. */
-public final class TypeNames {
-
- public static final ClassName ABSTRACT_PRODUCER = ClassName.get(AbstractProducer.class);
- public static final ClassName DEPENDENCY_METHOD_PRODUCER =
- ClassName.get(DependencyMethodProducer.class);
- 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 INSTANCE_FACTORY = ClassName.get(InstanceFactory.class);
- public static final ClassName LAZY = ClassName.get(Lazy.class);
- public static final ClassName LIST = ClassName.get(List.class);
- public static final ClassName LISTENABLE_FUTURE = ClassName.get(ListenableFuture.class);
- public static final ClassName MAP_FACTORY = ClassName.get(MapFactory.class);
- public static final ClassName MAP_OF_PRODUCED_PRODUCER =
- ClassName.get(MapOfProducedProducer.class);
- public static final ClassName MAP_OF_PRODUCER_PRODUCER =
- ClassName.get(MapOfProducerProducer.class);
- public static final ClassName MAP_PRODUCER = ClassName.get(MapProducer.class);
- public static final ClassName MAP_PROVIDER_FACTORY = ClassName.get(MapProviderFactory.class);
- public static final ClassName MEMBERS_INJECTOR = ClassName.get(MembersInjector.class);
- public static final ClassName MEMBERS_INJECTORS = ClassName.get(MembersInjectors.class);
- public static final ClassName PRODUCER_TOKEN = ClassName.get(ProducerToken.class);
- 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 PRODUCTION_COMPONENT_MONITOR_FACTORY =
- ClassName.get(ProductionComponentMonitor.Factory.class);
- public static final ClassName PROVIDER = ClassName.get(Provider.class);
- public static final ClassName PROVIDER_OF_LAZY = ClassName.get(ProviderOfLazy.class);
- public static final ClassName SET = ClassName.get(Set.class);
- public static final ClassName SET_FACTORY = ClassName.get(SetFactory.class);
- public static final ClassName SET_OF_PRODUCED_PRODUCER =
- ClassName.get(SetOfProducedProducer.class);
- public static final ClassName SET_PRODUCER = ClassName.get(SetProducer.class);
- public static final ClassName SINGLE_CHECK = ClassName.get(SingleCheck.class);
-
- /**
- * {@link TypeName#VOID} is lowercase-v {@code void} whereas this represents the class, {@link
- * Void}.
- */
- public static final ClassName VOID_CLASS = ClassName.get(Void.class);
-
- public static ParameterizedTypeName abstractProducerOf(TypeName typeName) {
- return ParameterizedTypeName.get(ABSTRACT_PRODUCER, typeName);
- }
-
- public static ParameterizedTypeName factoryOf(TypeName factoryType) {
- return ParameterizedTypeName.get(FACTORY, factoryType);
- }
-
- public static ParameterizedTypeName lazyOf(TypeName typeName) {
- return ParameterizedTypeName.get(LAZY, typeName);
- }
-
- public static ParameterizedTypeName listOf(TypeName typeName) {
- return ParameterizedTypeName.get(LIST, typeName);
- }
-
- public static ParameterizedTypeName listenableFutureOf(TypeName typeName) {
- return ParameterizedTypeName.get(LISTENABLE_FUTURE, typeName);
- }
-
- public static ParameterizedTypeName membersInjectorOf(TypeName membersInjectorType) {
- return ParameterizedTypeName.get(MEMBERS_INJECTOR, membersInjectorType);
- }
-
- public static ParameterizedTypeName producedOf(TypeName typeName) {
- return ParameterizedTypeName.get(PRODUCED, typeName);
- }
-
- public static ParameterizedTypeName producerOf(TypeName typeName) {
- return ParameterizedTypeName.get(PRODUCER, typeName);
- }
-
- public static ParameterizedTypeName dependencyMethodProducerOf(TypeName typeName) {
- return ParameterizedTypeName.get(DEPENDENCY_METHOD_PRODUCER, typeName);
- }
-
- public static ParameterizedTypeName providerOf(TypeName typeName) {
- return ParameterizedTypeName.get(PROVIDER, typeName);
- }
-
- public static ParameterizedTypeName setOf(TypeName elementType) {
- return ParameterizedTypeName.get(SET, elementType);
- }
-
- /**
- * 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 TypeNames() {}
-}
diff --git a/java/dagger/internal/codegen/javapoet/TypeSpecs.java b/java/dagger/internal/codegen/javapoet/TypeSpecs.java
deleted file mode 100644
index 8ec8747..0000000
--- a/java/dagger/internal/codegen/javapoet/TypeSpecs.java
+++ /dev/null
@@ -1,46 +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.javapoet;
-
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeSpec;
-import javax.lang.model.element.TypeElement;
-
-/** Convenience methods for use with JavaPoet's {@link TypeSpec}. */
-public final class TypeSpecs {
-
- /**
- * If {@code supertype} is a class, adds it as a superclass for {@code typeBuilder}; if it is an
- * interface, adds it as a superinterface.
- *
- * @return {@code typeBuilder}
- */
- @CanIgnoreReturnValue
- public static TypeSpec.Builder addSupertype(TypeSpec.Builder typeBuilder, TypeElement supertype) {
- switch (supertype.getKind()) {
- case CLASS:
- return typeBuilder.superclass(ClassName.get(supertype));
- case INTERFACE:
- return typeBuilder.addSuperinterface(ClassName.get(supertype));
- default:
- throw new AssertionError(supertype + " is neither a class nor an interface.");
- }
- }
-
- private TypeSpecs() {}
-}
diff --git a/java/dagger/internal/codegen/kythe_plugin_deploy.jar b/java/dagger/internal/codegen/kythe_plugin_deploy.jar
deleted file mode 100644
index 3a1eed2..0000000
--- a/java/dagger/internal/codegen/kythe_plugin_deploy.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/internal/codegen/langmodel/Accessibility.java b/java/dagger/internal/codegen/langmodel/Accessibility.java
deleted file mode 100644
index 62c1fbd..0000000
--- a/java/dagger/internal/codegen/langmodel/Accessibility.java
+++ /dev/null
@@ -1,276 +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.langmodel;
-
-import static com.google.auto.common.MoreElements.getPackage;
-import static com.google.common.base.Preconditions.checkArgument;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.google.auto.common.MoreElements;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-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.TypeVisitor;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.SimpleElementVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/**
- * Utility methods for determining whether a {@linkplain TypeMirror type} or an {@linkplain Element
- * element} is accessible given the rules outlined in <a
- * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6">section 6.6 of the
- * Java Language Specification</a>.
- *
- * <p>This class only provides an approximation for accessibility. It does not always yield the same
- * result as the compiler, but will always err on the side of declaring something inaccessible. This
- * ensures that using this class will never result in generating code that will not compile.
- *
- * <p>Whenever compiler independence is not a requirement, the compiler-specific implementation of
- * this functionality should be preferred. For example, {@link
- * com.sun.source.util.Trees#isAccessible(com.sun.source.tree.Scope, TypeElement)} would be
- * preferable for {@code javac}.
- */
-public final class Accessibility {
- /** Returns true if the given type can be referenced from any package. */
- public static boolean isTypePubliclyAccessible(TypeMirror type) {
- return type.accept(new TypeAccessibilityVisitor(), null);
- }
-
- /** Returns true if the given type can be referenced from code in the given package. */
- public static boolean isTypeAccessibleFrom(TypeMirror type, String packageName) {
- return type.accept(new TypeAccessibilityVisitor(packageName), null);
- }
-
- private static boolean isTypeAccessibleFrom(TypeMirror type, Optional<String> packageName) {
- return type.accept(new TypeAccessibilityVisitor(packageName), null);
- }
-
- private static final class TypeAccessibilityVisitor extends SimpleTypeVisitor6<Boolean, Void> {
- final Optional<String> packageName;
-
- TypeAccessibilityVisitor() {
- this(Optional.empty());
- }
-
- TypeAccessibilityVisitor(String packageName) {
- this(Optional.of(packageName));
- }
-
- TypeAccessibilityVisitor(Optional<String> packageName) {
- this.packageName = packageName;
- }
-
- boolean isAccessible(TypeMirror type) {
- return type.accept(this, null);
- }
-
- @Override
- public Boolean visitNoType(NoType type, Void p) {
- return true;
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType type, Void p) {
- if (!isAccessible(type.getEnclosingType())) {
- // TODO(gak): investigate this check. see comment in Binding
- return false;
- }
- if (!isElementAccessibleFrom(type.asElement(), packageName)) {
- return false;
- }
- for (TypeMirror typeArgument : type.getTypeArguments()) {
- if (!isAccessible(typeArgument)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Boolean visitArray(ArrayType type, Void p) {
- return type.getComponentType().accept(this, null);
- }
-
- @Override
- public Boolean visitPrimitive(PrimitiveType type, Void p) {
- return true;
- }
-
- @Override
- public Boolean visitNull(NullType type, Void p) {
- return true;
- }
-
- @Override
- public Boolean visitTypeVariable(TypeVariable type, Void p) {
- // a _reference_ to a type variable is always accessible
- return true;
- }
-
- @Override
- public Boolean visitWildcard(WildcardType type, Void p) {
- if (type.getExtendsBound() != null && !isAccessible(type.getExtendsBound())) {
- return false;
- }
- if (type.getSuperBound() != null && !isAccessible(type.getSuperBound())) {
- return false;
- }
- return true;
- }
-
- @Override
- protected Boolean defaultAction(TypeMirror type, Void p) {
- throw new IllegalArgumentException(
- String.format(
- "%s of kind %s should not be checked for accessibility", type, type.getKind()));
- }
- }
-
- /** Returns true if the given element can be referenced from any package. */
- public static boolean isElementPubliclyAccessible(Element element) {
- return element.accept(new ElementAccessibilityVisitor(), null);
- }
-
- /** Returns true if the given element can be referenced from code in the given package. */
- // TODO(gak): account for protected
- public static boolean isElementAccessibleFrom(Element element, String packageName) {
- return element.accept(new ElementAccessibilityVisitor(packageName), null);
- }
-
- private static boolean isElementAccessibleFrom(Element element, Optional<String> packageName) {
- return element.accept(new ElementAccessibilityVisitor(packageName), null);
- }
-
- /** Returns true if the given element can be referenced from other code in its own package. */
- public static boolean isElementAccessibleFromOwnPackage(Element element) {
- return isElementAccessibleFrom(
- element, MoreElements.getPackage(element).getQualifiedName().toString());
- }
-
- private static final class ElementAccessibilityVisitor
- extends SimpleElementVisitor6<Boolean, Void> {
- final Optional<String> packageName;
-
- ElementAccessibilityVisitor() {
- this(Optional.empty());
- }
-
- ElementAccessibilityVisitor(String packageName) {
- this(Optional.of(packageName));
- }
-
- ElementAccessibilityVisitor(Optional<String> packageName) {
- this.packageName = packageName;
- }
-
- @Override
- public Boolean visitPackage(PackageElement element, Void p) {
- return true;
- }
-
- @Override
- public Boolean visitType(TypeElement element, Void p) {
- switch (element.getNestingKind()) {
- case MEMBER:
- return accessibleMember(element);
- case TOP_LEVEL:
- return accessibleModifiers(element);
- case ANONYMOUS:
- case LOCAL:
- return false;
- }
- throw new AssertionError();
- }
-
- boolean accessibleMember(Element element) {
- if (!element.getEnclosingElement().accept(this, null)) {
- return false;
- }
- return accessibleModifiers(element);
- }
-
- boolean accessibleModifiers(Element element) {
- if (element.getModifiers().contains(PUBLIC)) {
- return true;
- } else if (element.getModifiers().contains(PRIVATE)) {
- return false;
- } else if (packageName.isPresent()
- && getPackage(element).getQualifiedName().contentEquals(packageName.get())) {
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public Boolean visitTypeParameter(TypeParameterElement element, Void p) {
- throw new IllegalArgumentException(
- "It does not make sense to check the accessibility of a type parameter");
- }
-
- @Override
- public Boolean visitExecutable(ExecutableElement element, Void p) {
- return accessibleMember(element);
- }
-
- @Override
- public Boolean visitVariable(VariableElement element, Void p) {
- ElementKind kind = element.getKind();
- checkArgument(kind.isField(), "checking a variable that isn't a field: %s", kind);
- return accessibleMember(element);
- }
- }
-
- private static final TypeVisitor<Boolean, Optional<String>> RAW_TYPE_ACCESSIBILITY_VISITOR =
- new SimpleTypeVisitor8<Boolean, Optional<String>>() {
- @Override
- protected Boolean defaultAction(TypeMirror e, Optional<String> requestingPackage) {
- return isTypeAccessibleFrom(e, requestingPackage);
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType t, Optional<String> requestingPackage) {
- return isElementAccessibleFrom(t.asElement(), requestingPackage);
- }
- };
-
- /** Returns true if the raw type of {@code type} is accessible from the given package. */
- public static boolean isRawTypeAccessible(TypeMirror type, String requestingPackage) {
- return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.of(requestingPackage));
- }
-
- /** Returns true if the raw type of {@code type} is accessible from any package. */
- public static boolean isRawTypePubliclyAccessible(TypeMirror type) {
- return type.accept(RAW_TYPE_ACCESSIBILITY_VISITOR, Optional.empty());
- }
-
- private Accessibility() {}
-}
diff --git a/java/dagger/internal/codegen/langmodel/BUILD b/java/dagger/internal/codegen/langmodel/BUILD
deleted file mode 100644
index 16fa5d8..0000000
--- a/java/dagger/internal/codegen/langmodel/BUILD
+++ /dev/null
@@ -1,31 +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-specific extensions to the javax.lang.model APIs
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "langmodel",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen:bootstrap_compiler_plugin"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "@google_bazel_common//third_party/java/auto:common",
- "@google_bazel_common//third_party/java/guava",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
diff --git a/java/dagger/internal/codegen/langmodel/DaggerElements.java b/java/dagger/internal/codegen/langmodel/DaggerElements.java
deleted file mode 100644
index 873ad3d..0000000
--- a/java/dagger/internal/codegen/langmodel/DaggerElements.java
+++ /dev/null
@@ -1,316 +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.langmodel;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
-import static com.google.auto.common.MoreElements.hasModifiers;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Lists.asList;
-import static java.util.Comparator.comparing;
-import static java.util.stream.Collectors.toSet;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.graph.Traverser;
-import com.squareup.javapoet.ClassName;
-import dagger.Reusable;
-import java.io.Writer;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Predicate;
-import javax.annotation.processing.ProcessingEnvironment;
-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.ElementVisitor;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleElementVisitor8;
-import javax.lang.model.util.Types;
-
-/** Extension of {@link Elements} that adds Dagger-specific methods. */
-@Reusable
-public final class DaggerElements implements Elements {
-
- private final Elements elements;
- private final Types types;
-
- public DaggerElements(Elements elements, Types types) {
- this.elements = checkNotNull(elements);
- this.types = checkNotNull(types);
- }
-
- public DaggerElements(ProcessingEnvironment processingEnv) {
- this(processingEnv.getElementUtils(), processingEnv.getTypeUtils());
- }
-
- /**
- * Returns {@code true} if {@code encloser} is equal to {@code enclosed} or recursively encloses
- * it.
- */
- public static boolean elementEncloses(TypeElement encloser, Element enclosed) {
- return Iterables.contains(GET_ENCLOSED_ELEMENTS.breadthFirst(encloser), enclosed);
- }
-
- private static final Traverser<Element> GET_ENCLOSED_ELEMENTS =
- Traverser.forTree(Element::getEnclosedElements);
-
- public ImmutableSet<ExecutableElement> getUnimplementedMethods(TypeElement type) {
- return FluentIterable.from(getLocalAndInheritedMethods(type, types, elements))
- .filter(hasModifiers(ABSTRACT))
- .toSet();
- }
-
- /** Returns the type element for a class. */
- public TypeElement getTypeElement(Class<?> clazz) {
- return getTypeElement(clazz.getCanonicalName());
- }
-
- @Override
- public TypeElement getTypeElement(CharSequence name) {
- return elements.getTypeElement(name);
- }
-
- /** Returns the type element for a class name. */
- public TypeElement getTypeElement(ClassName className) {
- return getTypeElement(className.withoutAnnotations().toString());
- }
-
- /** Returns the argument or the closest enclosing element that is a {@link TypeElement}. */
- public static TypeElement closestEnclosingTypeElement(Element element) {
- return element.accept(CLOSEST_ENCLOSING_TYPE_ELEMENT, null);
- }
-
- private static final ElementVisitor<TypeElement, Void> CLOSEST_ENCLOSING_TYPE_ELEMENT =
- new SimpleElementVisitor8<TypeElement, Void>() {
- @Override
- protected TypeElement defaultAction(Element element, Void p) {
- return element.getEnclosingElement().accept(this, null);
- }
-
- @Override
- public TypeElement visitType(TypeElement type, Void p) {
- return type;
- }
- };
-
- /**
- * Compares elements according to their declaration order among siblings. Only valid to compare
- * elements enclosed by the same parent.
- */
- public static final Comparator<Element> DECLARATION_ORDER =
- comparing(element -> siblings(element).indexOf(element));
-
- // For parameter elements, element.getEnclosingElement().getEnclosedElements() is empty. So
- // instead look at the parameter list of the enclosing executable.
- private static List<? extends Element> siblings(Element element) {
- return element.getKind().equals(ElementKind.PARAMETER)
- ? asExecutable(element.getEnclosingElement()).getParameters()
- : element.getEnclosingElement().getEnclosedElements();
- }
-
- /**
- * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
- * AnnotationMirror#getAnnotationType() annotation type} has the same canonical name as any of
- * that of {@code annotationClasses}.
- */
- public static boolean isAnyAnnotationPresent(
- Element element, Iterable<? extends Class<? extends Annotation>> annotationClasses) {
- for (Class<? extends Annotation> annotation : annotationClasses) {
- if (MoreElements.isAnnotationPresent(element, annotation)) {
- return true;
- }
- }
- return false;
- }
-
- @SafeVarargs
- public static boolean isAnyAnnotationPresent(
- Element element,
- Class<? extends Annotation> first,
- Class<? extends Annotation>... otherAnnotations) {
- return isAnyAnnotationPresent(element, asList(first, otherAnnotations));
- }
-
- /**
- * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
- * AnnotationMirror#getAnnotationType() annotation type} is equivalent to {@code annotationType}.
- */
- public static boolean isAnnotationPresent(Element element, TypeMirror annotationType) {
- return element.getAnnotationMirrors().stream()
- .map(AnnotationMirror::getAnnotationType)
- .anyMatch(candidate -> MoreTypes.equivalence().equivalent(candidate, annotationType));
- }
-
- /**
- * Returns the annotation present on {@code element} whose type is {@code first} or within {@code
- * rest}, checking each annotation type in order.
- */
- @SafeVarargs
- public static Optional<AnnotationMirror> getAnyAnnotation(
- Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
- return getAnyAnnotation(element, asList(first, rest));
- }
-
- /**
- * Returns the annotation present on {@code element} whose type is in {@code annotations},
- * checking each annotation type in order.
- */
- public static Optional<AnnotationMirror> getAnyAnnotation(
- Element element, Collection<? extends Class<? extends Annotation>> annotations) {
- return element.getAnnotationMirrors().stream()
- .filter(hasAnnotationTypeIn(annotations))
- .map((AnnotationMirror a) -> a) // Avoid returning Optional<? extends AnnotationMirror>.
- .findFirst();
- }
-
- /** Returns the annotations present on {@code element} of all types. */
- @SafeVarargs
- public static ImmutableSet<AnnotationMirror> getAllAnnotations(
- Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
- return ImmutableSet.copyOf(
- Iterables.filter(
- element.getAnnotationMirrors(), hasAnnotationTypeIn(asList(first, rest))::test));
- }
-
- /**
- * Returns an {@link AnnotationMirror} for the annotation of type {@code annotationClass} on
- * {@code element}, or {@link Optional#empty()} if no such annotation exists. This method is a
- * safer alternative to calling {@link Element#getAnnotation} as it avoids any interaction with
- * annotation proxies.
- */
- public static Optional<AnnotationMirror> getAnnotationMirror(
- Element element, Class<? extends Annotation> annotationClass) {
- return Optional.ofNullable(MoreElements.getAnnotationMirror(element, annotationClass).orNull());
- }
-
- private static Predicate<AnnotationMirror> hasAnnotationTypeIn(
- Collection<? extends Class<? extends Annotation>> annotations) {
- Set<String> annotationClassNames =
- annotations.stream().map(Class::getCanonicalName).collect(toSet());
- return annotation ->
- annotationClassNames.contains(
- MoreTypes.asTypeElement(annotation.getAnnotationType()).getQualifiedName().toString());
- }
-
- public static ImmutableSet<String> suppressedWarnings(Element element) {
- SuppressWarnings suppressedWarnings = element.getAnnotation(SuppressWarnings.class);
- if (suppressedWarnings == null) {
- return ImmutableSet.of();
- }
- return ImmutableSet.copyOf(suppressedWarnings.value());
- }
-
- /**
- * Invokes {@link Elements#getTypeElement(CharSequence)}, throwing {@link TypeNotPresentException}
- * if it is not accessible in the current compilation.
- */
- public TypeElement checkTypePresent(String typeName) {
- TypeElement type = elements.getTypeElement(typeName);
- if (type == null) {
- throw new TypeNotPresentException(typeName, null);
- }
- return type;
- }
-
- @Override
- public PackageElement getPackageElement(CharSequence name) {
- return elements.getPackageElement(name);
- }
-
- @Override
- public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults(
- AnnotationMirror a) {
- return elements.getElementValuesWithDefaults(a);
- }
-
- @Override
- public String getDocComment(Element e) {
- return elements.getDocComment(e);
- }
-
- @Override
- public boolean isDeprecated(Element e) {
- return elements.isDeprecated(e);
- }
-
- @Override
- public Name getBinaryName(TypeElement type) {
- return elements.getBinaryName(type);
- }
-
- @Override
- public PackageElement getPackageOf(Element type) {
- return elements.getPackageOf(type);
- }
-
- @Override
- public List<? extends Element> getAllMembers(TypeElement type) {
- return elements.getAllMembers(type);
- }
-
- @Override
- public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
- return elements.getAllAnnotationMirrors(e);
- }
-
- @Override
- public boolean hides(Element hider, Element hidden) {
- return elements.hides(hider, hidden);
- }
-
- @Override
- public boolean overrides(
- ExecutableElement overrider, ExecutableElement overridden, TypeElement type) {
- return elements.overrides(overrider, overridden, type);
- }
-
- @Override
- public String getConstantExpression(Object value) {
- return elements.getConstantExpression(value);
- }
-
- @Override
- public void printElements(Writer w, Element... elements) {
- this.elements.printElements(w, elements);
- }
-
- @Override
- public Name getName(CharSequence cs) {
- return elements.getName(cs);
- }
-
- @Override
- public boolean isFunctionalInterface(TypeElement type) {
- return elements.isFunctionalInterface(type);
- }
-}
diff --git a/java/dagger/internal/codegen/langmodel/DaggerTypes.java b/java/dagger/internal/codegen/langmodel/DaggerTypes.java
deleted file mode 100644
index e588fbd..0000000
--- a/java/dagger/internal/codegen/langmodel/DaggerTypes.java
+++ /dev/null
@@ -1,358 +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.langmodel;
-
-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 com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.graph.Traverser;
-import com.google.common.util.concurrent.FluentFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.squareup.javapoet.ClassName;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-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.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ErrorType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.NoType;
-import javax.lang.model.type.NullType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.SimpleTypeVisitor8;
-import javax.lang.model.util.Types;
-
-/** Extension of {@link Types} that adds Dagger-specific methods. */
-public final class DaggerTypes implements Types {
- private final Types types;
- private final DaggerElements elements;
-
- @Inject
- public DaggerTypes(Types types, DaggerElements elements) {
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
- }
-
- /**
- * Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty
- * {@link Optional} is returned if there is no non-{@link Object} superclass.
- */
- public Optional<DeclaredType> nonObjectSuperclass(DeclaredType type) {
- return Optional.ofNullable(MoreTypes.nonObjectSuperclass(types, elements, type).orNull());
- }
-
- /**
- * Returns the {@linkplain #directSupertypes(TypeMirror) supertype}s of a type in breadth-first
- * order.
- */
- public Iterable<TypeMirror> supertypes(TypeMirror type) {
- return Traverser.<TypeMirror>forGraph(this::directSupertypes).breadthFirst(type);
- }
-
- /**
- * Returns {@code type}'s single type argument.
- *
- * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
- *
- * @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
- * than one type arguments.
- */
- public TypeMirror unwrapType(TypeMirror type) {
- TypeMirror unwrapped = unwrapTypeOrDefault(type, null);
- checkArgument(unwrapped != null, "%s is a raw type", type);
- return unwrapped;
- }
-
- /**
- * Returns {@code type}'s single type argument, if one exists, or {@link Object} if not.
- *
- * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
- *
- * @throws IllegalArgumentException if {@code type} is not a declared type or has more than one
- * type argument.
- */
- public TypeMirror unwrapTypeOrObject(TypeMirror type) {
- return unwrapTypeOrDefault(type, elements.getTypeElement(Object.class).asType());
- }
-
- private TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) {
- DeclaredType declaredType = MoreTypes.asDeclared(type);
- TypeElement typeElement = MoreElements.asType(declaredType.asElement());
- checkArgument(
- !typeElement.getTypeParameters().isEmpty(),
- "%s does not have a type parameter",
- typeElement.getQualifiedName());
- return getOnlyElement(declaredType.getTypeArguments(), defaultType);
- }
-
- /**
- * Returns {@code type} wrapped in {@code wrappingClass}.
- *
- * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
- * Set.class}, this will return {@code Set<List<Number>>}.
- */
- public DeclaredType wrapType(TypeMirror type, Class<?> wrappingClass) {
- return types.getDeclaredType(elements.getTypeElement(wrappingClass), type);
- }
-
- /**
- * Returns {@code type}'s single type argument wrapped in {@code wrappingClass}.
- *
- * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
- * Set.class}, this will return {@code Set<Number>}.
- *
- * <p>If {@code type} has no type parameters, returns a {@link TypeMirror} for {@code
- * wrappingClass} as a raw type.
- *
- * @throws IllegalArgumentException if {@code} has more than one type argument.
- */
- public DeclaredType rewrapType(TypeMirror type, Class<?> wrappingClass) {
- List<? extends TypeMirror> typeArguments = MoreTypes.asDeclared(type).getTypeArguments();
- TypeElement wrappingType = elements.getTypeElement(wrappingClass);
- switch (typeArguments.size()) {
- case 0:
- return getDeclaredType(wrappingType);
- case 1:
- return getDeclaredType(wrappingType, getOnlyElement(typeArguments));
- default:
- throw new IllegalArgumentException(type + " has more than 1 type argument");
- }
- }
-
- /**
- * Returns a publicly accessible type based on {@code type}:
- *
- * <ul>
- * <li>If {@code type} is publicly accessible, returns it.
- * <li>If not, but {@code type}'s raw type is publicly accessible, returns the raw type.
- * <li>Otherwise returns {@link Object}.
- * </ul>
- */
- public TypeMirror publiclyAccessibleType(TypeMirror type) {
- return accessibleType(
- type, Accessibility::isTypePubliclyAccessible, Accessibility::isRawTypePubliclyAccessible);
- }
-
- /**
- * Returns an accessible type in {@code requestingClass}'s package based on {@code type}:
- *
- * <ul>
- * <li>If {@code type} is accessible from the package, returns it.
- * <li>If not, but {@code type}'s raw type is accessible from the package, returns the raw type.
- * <li>Otherwise returns {@link Object}.
- * </ul>
- */
- public TypeMirror accessibleType(TypeMirror type, ClassName requestingClass) {
- return accessibleType(
- type,
- t -> Accessibility.isTypeAccessibleFrom(t, requestingClass.packageName()),
- t -> Accessibility.isRawTypeAccessible(t, requestingClass.packageName()));
- }
-
- private TypeMirror accessibleType(
- TypeMirror type,
- Predicate<TypeMirror> accessibilityPredicate,
- Predicate<TypeMirror> rawTypeAccessibilityPredicate) {
- if (accessibilityPredicate.test(type)) {
- return type;
- } else if (type.getKind().equals(TypeKind.DECLARED)
- && rawTypeAccessibilityPredicate.test(type)) {
- return getDeclaredType(MoreTypes.asTypeElement(type));
- } else {
- return elements.getTypeElement(Object.class).asType();
- }
- }
-
- /**
- * Throws {@link TypeNotPresentException} if {@code type} is an {@link
- * javax.lang.model.type.ErrorType}.
- */
- public static void checkTypePresent(TypeMirror type) {
- type.accept(
- // TODO(ronshapiro): Extract a base class that visits all components of a complex type
- // and put it in auto.common
- new SimpleTypeVisitor8<Void, Void>() {
- @Override
- public Void visitArray(ArrayType arrayType, Void p) {
- return arrayType.getComponentType().accept(this, p);
- }
-
- @Override
- public Void visitDeclared(DeclaredType declaredType, Void p) {
- declaredType.getTypeArguments().forEach(t -> t.accept(this, p));
- return null;
- }
-
- @Override
- public Void visitError(ErrorType errorType, Void p) {
- throw new TypeNotPresentException(type.toString(), null);
- }
- },
- null);
- }
-
- private static final ImmutableSet<Class<?>> FUTURE_TYPES =
- ImmutableSet.of(ListenableFuture.class, FluentFuture.class);
-
- public static boolean isFutureType(TypeMirror type) {
- return FUTURE_TYPES.stream().anyMatch(t -> MoreTypes.isTypeOf(t, type));
- }
-
- public static boolean hasTypeVariable(TypeMirror type) {
- return type.accept(
- new SimpleTypeVisitor8<Boolean, Void>() {
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType.getComponentType().accept(this, p);
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType declaredType, Void p) {
- return declaredType.getTypeArguments().stream().anyMatch(type -> type.accept(this, p));
- }
-
- @Override
- public Boolean visitTypeVariable(TypeVariable t, Void aVoid) {
- return true;
- }
-
- @Override
- protected Boolean defaultAction(TypeMirror e, Void aVoid) {
- return false;
- }
- },
- null);
- }
-
- /**
- * Resolves the type of the given executable element as a member of the given type. This may
- * resolve type variables to concrete types, etc.
- */
- public ExecutableType resolveExecutableType(ExecutableElement element, TypeMirror containerType) {
- return MoreTypes.asExecutable(asMemberOf(MoreTypes.asDeclared(containerType), element));
- }
-
- // Implementation of Types methods, delegating to types.
-
- @Override
- public Element asElement(TypeMirror t) {
- return types.asElement(t);
- }
-
- @Override
- public boolean isSameType(TypeMirror t1, TypeMirror t2) {
- return types.isSameType(t1, t2);
- }
-
- @Override
- public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
- return types.isSubtype(t1, t2);
- }
-
- @Override
- public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
- return types.isAssignable(t1, t2);
- }
-
- @Override
- public boolean contains(TypeMirror t1, TypeMirror t2) {
- return types.contains(t1, t2);
- }
-
- @Override
- public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
- return types.isSubsignature(m1, m2);
- }
-
- @Override
- public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
- return types.directSupertypes(t);
- }
-
- @Override
- public TypeMirror erasure(TypeMirror t) {
- return types.erasure(t);
- }
-
- @Override
- public TypeElement boxedClass(PrimitiveType p) {
- return types.boxedClass(p);
- }
-
- @Override
- public PrimitiveType unboxedType(TypeMirror t) {
- return types.unboxedType(t);
- }
-
- @Override
- public TypeMirror capture(TypeMirror t) {
- return types.capture(t);
- }
-
- @Override
- public PrimitiveType getPrimitiveType(TypeKind kind) {
- return types.getPrimitiveType(kind);
- }
-
- @Override
- public NullType getNullType() {
- return types.getNullType();
- }
-
- @Override
- public NoType getNoType(TypeKind kind) {
- return types.getNoType(kind);
- }
-
- @Override
- public ArrayType getArrayType(TypeMirror componentType) {
- return types.getArrayType(componentType);
- }
-
- @Override
- public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
- return types.getWildcardType(extendsBound, superBound);
- }
-
- @Override
- public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
- return types.getDeclaredType(typeElem, typeArgs);
- }
-
- @Override
- public DeclaredType getDeclaredType(
- DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) {
- return types.getDeclaredType(containing, typeElem, typeArgs);
- }
-
- @Override
- public TypeMirror asMemberOf(DeclaredType containing, Element element) {
- return types.asMemberOf(containing, element);
- }
-}
diff --git a/java/dagger/internal/codegen/package-info.java b/java/dagger/internal/codegen/package-info.java
deleted file mode 100644
index c8cc404..0000000
--- a/java/dagger/internal/codegen/package-info.java
+++ /dev/null
@@ -1,20 +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.
- */
-
-@CheckReturnValue
-package dagger.internal.codegen;
-
-import com.google.errorprone.annotations.CheckReturnValue;
diff --git a/java/dagger/internal/codegen/serialization/BUILD b/java/dagger/internal/codegen/serialization/BUILD
deleted file mode 100644
index 2bc02b4..0000000
--- a/java/dagger/internal/codegen/serialization/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:
-# 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
deleted file mode 100644
index 1449e9d..0000000
--- a/java/dagger/internal/codegen/serialization/ProtoSerialization.java
+++ /dev/null
@@ -1,81 +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.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
deleted file mode 100644
index e6c9577..0000000
--- a/java/dagger/internal/codegen/serialization/serialization.proto
+++ /dev/null
@@ -1,167 +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.
- */
-
-// 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/doc-files/ReferenceReleasingProvider-statemachine.png b/java/dagger/internal/doc-files/ReferenceReleasingProvider-statemachine.png
deleted file mode 100644
index 8195dc0..0000000
--- a/java/dagger/internal/doc-files/ReferenceReleasingProvider-statemachine.png
+++ /dev/null
Binary files differ
diff --git a/java/dagger/model/BUILD b/java/dagger/model/BUILD
deleted file mode 100644
index 5fe0db3..0000000
--- a/java/dagger/model/BUILD
+++ /dev/null
@@ -1,61 +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's core APIs exposed for plugins
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-
-INTERNAL_PROXIES = ["BindingGraphProxies.java"]
-
-filegroup(
- name = "model-srcs",
- srcs = glob(
- ["*.java"],
- exclude = INTERNAL_PROXIES,
- ),
-)
-
-java_library(
- name = "model",
- srcs = [":model-srcs"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "//java/dagger:core",
- "//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",
- ],
-)
-
-java_library(
- name = "internal-proxies",
- srcs = INTERNAL_PROXIES,
- tags = ["maven:merged"],
- deps = [
- ":model",
- "@google_bazel_common//third_party/java/guava",
- ],
-)
diff --git a/java/dagger/model/Binding.java b/java/dagger/model/Binding.java
deleted file mode 100644
index 81aba00..0000000
--- a/java/dagger/model/Binding.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.model;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph.MaybeBinding;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/**
- * The association between a {@link Key} and the way in which instances of the key are provided.
- * Includes any {@linkplain DependencyRequest dependencies} that are needed in order to provide the
- * instances.
- *
- * <p>If a binding is owned by more than one component, there is one {@code Binding} for every
- * owning component.
- */
-public interface Binding extends MaybeBinding {
- @Override
- ComponentPath componentPath();
-
- /** @deprecated This always returns {@code Optional.of(this)}. */
- @Override
- @Deprecated
- default Optional<Binding> binding() {
- return Optional.of(this);
- }
- /**
- * The dependencies of this binding. The order of the dependencies corresponds to the order in
- * which they will be injected when the binding is requested.
- */
- ImmutableSet<DependencyRequest> dependencies();
-
- /**
- * The {@link 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.
- */
- Optional<Element> bindingElement();
-
- /**
- * The {@link TypeElement} of the module which contributes this binding. Absent for bindings that
- * have no {@link #bindingElement() binding element}.
- */
- Optional<TypeElement> contributingModule();
-
- /**
- * Returns {@code true} if using this binding requires an instance of the {@link
- * #contributingModule()}.
- */
- boolean requiresModuleInstance();
-
- /** The scope of this binding if it has one. */
- Optional<Scope> scope();
-
- /**
- * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
- * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
- * non-nullable dependency requests}.
- */
- boolean isNullable();
-
- /** Returns {@code true} if this is a production binding, e.g. an {@code @Produces} method. */
- boolean isProduction();
-
- /** The kind of binding this instance represents. */
- BindingKind kind();
-
-}
diff --git a/java/dagger/model/BindingGraph.java b/java/dagger/model/BindingGraph.java
deleted file mode 100644
index 748bf38..0000000
--- a/java/dagger/model/BindingGraph.java
+++ /dev/null
@@ -1,466 +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.model;
-
-import static com.google.common.collect.Sets.intersection;
-import static com.google.common.graph.Graphs.inducedSubgraph;
-import static com.google.common.graph.Graphs.reachableNodes;
-import static com.google.common.graph.Graphs.transpose;
-import static dagger.internal.codegen.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;
-import com.google.common.graph.ImmutableNetwork;
-import com.google.common.graph.MutableNetwork;
-import com.google.common.graph.Network;
-import com.google.common.graph.NetworkBuilder;
-import dagger.Module;
-import java.util.Optional;
-import java.util.stream.Stream;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A graph of bindings, dependency requests, and components.
- *
- * <p>A {@link BindingGraph} represents one of the following:
- *
- * <ul>
- * <li>an entire component hierarchy rooted at a {@link dagger.Component} or {@link
- * dagger.producers.ProductionComponent}
- * <li>a partial component hierarchy rooted at a {@link dagger.Subcomponent} or {@link
- * dagger.producers.ProductionSubcomponent} (only when {@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()} ()}
- * </ul>
- *
- * In the case of a {@link BindingGraph} representing a module, the root {@link ComponentNode} will
- * actually represent the module type. The graph will also be a {@linkplain #isFullBindingGraph()
- * full binding graph}, which means it will contain all bindings in all modules, as well as nodes
- * for their dependencies. Otherwise it will contain only bindings that are reachable from at least
- * one {@linkplain #entryPointEdges() entry point}.
- *
- * <h3>Nodes</h3>
- *
- * <p>There is a <b>{@link Binding}</b> for each owned binding in the graph. If a binding is owned
- * by more than one component, there is one binding object for that binding for every owning
- * component.
- *
- * <p>There is a <b>{@linkplain ComponentNode component node}</b> (without a binding) for each
- * component in the graph.
- *
- * <h3>Edges</h3>
- *
- * <p>There is a <b>{@linkplain DependencyEdge dependency edge}</b> for each dependency request in
- * the graph. Its target node is the binding for the binding that satisfies the request. For entry
- * point dependency requests, the source node is the component node for the component for which it
- * is an entry point. For other dependency requests, the source node is the binding for the binding
- * that contains the request.
- *
- * <p>There is a <b>subcomponent edge</b> for each parent-child component relationship in the graph.
- * The target node is the component node for the child component. For subcomponents defined by a
- * {@linkplain SubcomponentCreatorBindingEdge subcomponent creator binding} (either a method on the
- * component or a set of {@code @Module.subcomponents} annotation values), the source node is the
- * binding for the {@code @Subcomponent.Builder} type. For subcomponents defined by {@linkplain
- * ChildFactoryMethodEdge subcomponent factory methods}, the source node is the component node for
- * the parent.
- *
- * <p><b>Note that this API is experimental and will change.</b>
- */
-@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 final String toString() {
- return network().toString();
- }
-
- /**
- * Returns {@code true} if this graph was constructed from a module for full binding graph
- * validation.
- *
- * @deprecated use {@link #isFullBindingGraph()} to tell if this is a full binding graph, or
- * {@link ComponentNode#isRealComponent() rootComponentNode().isRealComponent()} to tell if
- * the root component node is really a component or derived from a module. Dagger can generate
- * full binding graphs for components and subcomponents as well as modules.
- */
- @Deprecated
- public final boolean isModuleBindingGraph() {
- return !rootComponentNode().isRealComponent();
- }
-
- /**
- * Returns {@code true} if this is a full binding graph, which contains all bindings installed in
- * the component, or {@code false} if it is a reachable binding graph, which contains only
- * bindings that are reachable from at least one {@linkplain #entryPointEdges() entry point}.
- *
- * @see <a href="https://dagger.dev/compiler-options#full-binding-graph-validation">Full binding
- * graph validation</a>
- */
- public abstract boolean isFullBindingGraph();
-
- /**
- * Returns {@code true} if the {@link #rootComponentNode()} is a subcomponent. This occurs in
- * ahead-of-time-subcomponents mode.
- *
- * @deprecated use {@link ComponentNode#isSubcomponent() rootComponentNode().isSubcomponent()}
- * instead
- */
- @Deprecated
- public final boolean isPartialBindingGraph() {
- return rootComponentNode().isSubcomponent();
- }
-
- /** Returns the bindings. */
- public final ImmutableSet<Binding> bindings() {
- return nodes(Binding.class);
- }
-
- /** Returns the bindings for a 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 final ImmutableSet<MissingBinding> missingBindings() {
- return nodes(MissingBinding.class);
- }
-
- /** Returns the component nodes. */
- public final ImmutableSet<ComponentNode> componentNodes() {
- return nodes(ComponentNode.class);
- }
-
- /** Returns the component node for a 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 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 final ComponentNode rootComponentNode() {
- return componentNodes().stream()
- .filter(node -> node.componentPath().atRoot())
- .findFirst()
- .get();
- }
-
- /** Returns the dependency edges. */
- public final ImmutableSet<DependencyEdge> dependencyEdges() {
- return dependencyEdgeStream().collect(toImmutableSet());
- }
-
- /**
- * Returns the dependency edges for the dependencies of a binding. For valid graphs, each {@link
- * DependencyRequest} will map to a single {@link DependencyEdge}. When conflicting bindings exist
- * for a key, the multimap will have several edges for that {@link DependencyRequest}. Graphs that
- * have no binding for a key will have an edge whose {@linkplain EndpointPair#target() target
- * node} is a {@link MissingBinding}.
- */
- public 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 final ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
- return dependencyEdgeStream()
- .filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
- .collect(toImmutableSet());
- }
-
- /**
- * Returns the dependency edges for the entry points of a given {@code component}. Each edge's
- * source node is that component's component node.
- */
- public final ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
- return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
- }
-
- private Stream<DependencyEdge> dependencyEdgeStream(Node node) {
- return network().outEdges(node).stream().flatMap(instancesOf(DependencyEdge.class));
- }
-
- /**
- * Returns the dependency edges for all entry points for all components and subcomponents. Each
- * edge's source node is a component node.
- */
- public final ImmutableSet<DependencyEdge> entryPointEdges() {
- return entryPointEdgeStream().collect(toImmutableSet());
- }
-
- /** Returns the binding or missing binding nodes that directly satisfy entry points. */
- public final ImmutableSet<MaybeBinding> entryPointBindings() {
- return entryPointEdgeStream()
- .map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
- .collect(toImmutableSet());
- }
-
- /**
- * Returns the edges for entry points that transitively depend on a binding or missing binding for
- * a key.
- */
- public final ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
- MaybeBinding binding) {
- ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
- Network<Node, DependencyEdge> subgraphDependingOnBinding =
- inducedSubgraph(
- dependencyGraph, reachableNodes(transpose(dependencyGraph).asGraph(), binding));
- return intersection(entryPointEdges(), subgraphDependingOnBinding.edges()).immutableCopy();
- }
-
- /** Returns the bindings that directly request a given binding as a dependency. */
- public 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 request as a dependency. Does not include
- * any {@link MissingBinding}s.
- *
- * @see #requestedMaybeMissingBindings(Binding)
- */
- public final ImmutableSet<Binding> requestedBindings(Binding binding) {
- return network().successors(binding).stream()
- .flatMap(instancesOf(Binding.class))
- .collect(toImmutableSet());
- }
-
- /**
- * Returns the bindings or missing bindings that a given binding directly requests as a
- * dependency.
- *
- * @see #requestedBindings(Binding)
- */
- public final ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
- return network().successors(binding).stream()
- .flatMap(instancesOf(MaybeBinding.class))
- .collect(toImmutableSet());
- }
-
- /** Returns a subnetwork that contains all nodes but only {@link DependencyEdge}s. */
- // TODO(dpb): Make public. Cache.
- private ImmutableNetwork<Node, DependencyEdge> dependencyGraph() {
- MutableNetwork<Node, DependencyEdge> dependencyGraph =
- NetworkBuilder.from(network())
- .expectedNodeCount(network().nodes().size())
- .expectedEdgeCount((int) dependencyEdgeStream().count())
- .build();
- network().nodes().forEach(dependencyGraph::addNode); // include disconnected nodes
- dependencyEdgeStream()
- .forEach(
- edge -> {
- EndpointPair<Node> endpoints = network().incidentNodes(edge);
- dependencyGraph.addEdge(endpoints.source(), endpoints.target(), edge);
- });
- return ImmutableNetwork.copyOf(dependencyGraph);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- private <N extends Node> ImmutableSet<N> nodes(Class<N> clazz) {
- return (ImmutableSet) nodesByClass().get(clazz);
- }
-
- private static final ImmutableSet<Class<? extends Node>> NODE_TYPES =
- ImmutableSet.of(Binding.class, MissingBinding.class, ComponentNode.class);
-
- @Memoized
- ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
- return network().nodes().stream()
- .collect(
- toImmutableSetMultimap(
- node ->
- NODE_TYPES.stream().filter(clazz -> clazz.isInstance(node)).findFirst().get(),
- node -> node));
- }
-
- private Stream<DependencyEdge> dependencyEdgeStream() {
- return network().edges().stream().flatMap(instancesOf(DependencyEdge.class));
- }
-
- private Stream<DependencyEdge> entryPointEdgeStream() {
- return dependencyEdgeStream().filter(DependencyEdge::isEntryPoint);
- }
-
- /**
- * An edge in the binding graph. Either a {@link DependencyEdge}, a {@link
- * ChildFactoryMethodEdge}, or a {@link SubcomponentCreatorBindingEdge}.
- */
- public interface Edge {}
-
- /**
- * An edge that represents a dependency on a binding.
- *
- * <p>Because one {@link DependencyRequest} may represent a dependency from two bindings (e.g., a
- * dependency of {@code Foo<String>} and {@code Foo<Number>} may have the same key and request
- * element), this class does not override {@link #equals(Object)} to use value semantics.
- *
- * <p>For entry points, the source node is the {@link ComponentNode} that contains the entry
- * point. Otherwise the source node is a {@link Binding}.
- *
- * <p>For dependencies on missing bindings, the target node is a {@link MissingBinding}. Otherwise
- * the target node is a {@link Binding}.
- */
- public interface DependencyEdge extends Edge {
- /** The dependency request. */
- DependencyRequest dependencyRequest();
-
- /** Returns {@code true} if this edge represents an entry point. */
- boolean isEntryPoint();
- }
-
- /**
- * An edge that represents a subcomponent factory method linking a parent component to a child
- * subcomponent.
- */
- public interface ChildFactoryMethodEdge extends Edge {
- /** The subcomponent factory method element. */
- ExecutableElement factoryMethod();
- }
-
- /**
- * An edge that represents the link between a parent component and a child subcomponent implied by
- * a subcomponent creator ({@linkplain dagger.Subcomponent.Builder builder} or {@linkplain
- * dagger.Subcomponent.Factory factory}) binding.
- *
- * <p>The {@linkplain com.google.common.graph.EndpointPair#source() source node} of this edge is a
- * {@link Binding} for the subcomponent creator {@link Key} and the {@linkplain
- * com.google.common.graph.EndpointPair#target() target node} is a {@link ComponentNode} for the
- * child subcomponent.
- */
- public interface SubcomponentCreatorBindingEdge extends Edge {
- /**
- * The modules that {@linkplain Module#subcomponents() declare the subcomponent} that generated
- * this edge. Empty if the parent component has a subcomponent creator method and there are no
- * declaring modules.
- */
- ImmutableSet<TypeElement> declaringModules();
- }
-
- /** A node in the binding graph. Either a {@link Binding} or a {@link ComponentNode}. */
- // TODO(dpb): Make all the node/edge types top-level.
- public interface Node {
- /** The component this node belongs to. */
- ComponentPath componentPath();
- }
-
- /** A node in the binding graph that is either a {@link Binding} or a {@link MissingBinding}. */
- public interface MaybeBinding extends Node {
-
- /** The component that owns the binding, or in which the binding is missing. */
- @Override
- ComponentPath componentPath();
-
- /** The key of the binding, or for which there is no binding. */
- Key key();
-
- /** The binding, or empty if missing. */
- Optional<Binding> binding();
- }
-
- /** A node in the binding graph that represents a missing binding for a key in a component. */
- @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. */
- public abstract Key key();
-
- /** @deprecated This always returns {@code Optional.empty()}. */
- @Override
- @Deprecated
- public final Optional<Binding> binding() {
- return Optional.empty();
- }
-
- @Override
- 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);
- }
-
- /**
- * A <b>component node</b> in the graph. Every entry point {@linkplain DependencyEdge dependency
- * edge}'s source node is a component node for the component containing the entry point.
- */
- public interface ComponentNode extends Node {
-
- /** The component represented by this node. */
- @Override
- ComponentPath componentPath();
-
- /**
- * Returns {@code true} if the component is a {@code @Subcomponent} or
- * {@code @ProductionSubcomponent}.
- */
- boolean isSubcomponent();
-
- /**
- * Returns {@code true} if the component is a real component, or {@code false} if it is a
- * fictional component based on a module.
- */
- boolean isRealComponent();
-
- /** The entry points on this component. */
- ImmutableSet<DependencyRequest> entryPoints();
-
- /** The scopes declared on this component. */
- ImmutableSet<Scope> scopes();
- }
-}
diff --git a/java/dagger/model/BindingGraphProxies.java b/java/dagger/model/BindingGraphProxies.java
deleted file mode 100644
index c450475..0000000
--- a/java/dagger/model/BindingGraphProxies.java
+++ /dev/null
@@ -1,41 +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.model;
-
-import com.google.common.graph.Network;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-
-/**
- * Exposes package-private constructors to the {@code dagger.internal.codegen} package. <em>This
- * class should only be used in the Dagger implementation and is not part of any documented
- * API.</em>
- */
-public final class BindingGraphProxies {
- /** Creates a new {@link BindingGraph}. */
- public static BindingGraph bindingGraph(Network<Node, Edge> network, boolean isFullBindingGraph) {
- return BindingGraph.create(network, isFullBindingGraph);
- }
-
- /** Creates a new {@link MissingBinding}. */
- public static MissingBinding missingBindingNode(ComponentPath component, Key key) {
- return MissingBinding.create(component, key);
- }
-
- private BindingGraphProxies() {}
-}
diff --git a/java/dagger/model/BindingKind.java b/java/dagger/model/BindingKind.java
deleted file mode 100644
index 20d7b42..0000000
--- a/java/dagger/model/BindingKind.java
+++ /dev/null
@@ -1,117 +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.model;
-
-/** Represents the different kinds of {@link Binding}s that can exist in a binding graph. */
-public enum BindingKind {
- /** A binding for an {@link javax.inject.Inject}-annotated constructor. */
- INJECTION,
-
- /** A binding for a {@link dagger.Provides}-annotated method. */
- PROVISION,
-
- /**
- * An implicit binding for a {@link dagger.Component}- or {@link
- * dagger.producers.ProductionComponent}-annotated type.
- */
- COMPONENT,
-
- /**
- * A binding for a provision method on a component's {@linkplain dagger.Component#dependencies()
- * dependency}.
- */
- COMPONENT_PROVISION,
-
- /**
- * A binding for an instance of a component's {@linkplain dagger.Component#dependencies()
- * dependency}.
- */
- COMPONENT_DEPENDENCY,
-
- /** A binding for a {@link dagger.MembersInjector} of a type. */
- MEMBERS_INJECTOR,
-
- /**
- * A binding for a subcomponent creator (a {@linkplain dagger.Subcomponent.Builder builder} or
- * {@linkplain dagger.Subcomponent.Factory factory}).
- *
- * @since 2.22 (previously named {@code SUBCOMPONENT_BUILDER})
- */
- SUBCOMPONENT_CREATOR,
-
- /** A binding for a {@link dagger.BindsInstance}-annotated builder method. */
- BOUND_INSTANCE,
-
- /** A binding for a {@link dagger.producers.Produces}-annotated method. */
- PRODUCTION,
-
- /**
- * A binding for a production method on a production component's {@linkplain
- * dagger.producers.ProductionComponent#dependencies()} dependency} that returns a {@link
- * com.google.common.util.concurrent.ListenableFuture} or {@link
- * com.google.common.util.concurrent.FluentFuture}. Methods on production component dependencies
- * that don't return a future are considered {@linkplain #COMPONENT_PROVISION component provision
- * bindings}.
- */
- COMPONENT_PRODUCTION,
-
- /**
- * A synthetic binding for a multibound set that depends on individual multibinding {@link
- * #PROVISION} or {@link #PRODUCTION} contributions.
- */
- MULTIBOUND_SET,
-
- /**
- * A synthetic binding for a multibound map that depends on the individual multibinding {@link
- * #PROVISION} or {@link #PRODUCTION} contributions.
- */
- MULTIBOUND_MAP,
-
- /**
- * A synthetic binding for {@code Optional} of a type or a {@link javax.inject.Provider}, {@link
- * dagger.Lazy}, or {@code Provider} of {@code Lazy} of a type. Generated by a {@link
- * dagger.BindsOptionalOf} declaration.
- */
- OPTIONAL,
-
- /**
- * A binding for {@link dagger.Binds}-annotated method that that delegates from requests for one
- * key to another.
- */
- // TODO(dpb,ronshapiro): This name is confusing and could use work. Not all usages of @Binds
- // bindings are simple delegations and we should have a name that better reflects that
- DELEGATE,
-
- /** A binding for a members injection method on a component. */
- MEMBERS_INJECTION,
- ;
-
- /**
- * Returns {@code true} if this is a kind of multibinding (not a contribution to a multibinding,
- * but the multibinding itself).
- */
- public boolean isMultibinding() {
- switch (this) {
- case MULTIBOUND_MAP:
- case MULTIBOUND_SET:
- return true;
-
- default:
- return false;
- }
- }
-}
diff --git a/java/dagger/model/ComponentPath.java b/java/dagger/model/ComponentPath.java
deleted file mode 100644
index 5a74c7a..0000000
--- a/java/dagger/model/ComponentPath.java
+++ /dev/null
@@ -1,101 +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.model;
-
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getLast;
-import static java.util.stream.Collectors.joining;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableList;
-import javax.lang.model.element.TypeElement;
-
-/** A path containing a component and all of its ancestor components. */
-@AutoValue
-public abstract class ComponentPath {
- /** Returns a new {@link ComponentPath} from {@code components}. */
- public static ComponentPath create(Iterable<TypeElement> components) {
- return new AutoValue_ComponentPath(ImmutableList.copyOf(components));
- }
-
- /**
- * Returns the component types, starting from the {@linkplain #rootComponent() root
- * component} and ending with the {@linkplain #currentComponent() current component}.
- */
- public abstract ImmutableList<TypeElement> components();
-
- /**
- * Returns the root {@link dagger.Component}- or {@link
- * dagger.producers.ProductionComponent}-annotated type
- */
- public final TypeElement rootComponent() {
- return components().get(0);
- }
-
- /** Returns the component at the end of the path. */
- @Memoized
- public TypeElement currentComponent() {
- return getLast(components());
- }
-
- /**
- * Returns the parent of the {@linkplain #currentComponent()} current component}.
- *
- * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
- */
- public final TypeElement parentComponent() {
- checkState(!atRoot());
- return components().reverse().get(1);
- }
-
- /**
- * Returns this path's parent path.
- *
- * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
- */
- // TODO(ronshapiro): consider memoizing this
- public final ComponentPath parent() {
- checkState(!atRoot());
- return create(components().subList(0, components().size() - 1));
- }
-
- /** Returns the path from the root component to the {@code child} of the current component. */
- public final ComponentPath childPath(TypeElement child) {
- return create(ImmutableList.<TypeElement>builder().addAll(components()).add(child).build());
- }
-
- /**
- * Returns {@code true} if the {@linkplain #currentComponent()} current component} is the
- * {@linkplain #rootComponent()} root component}.
- */
- public final boolean atRoot() {
- return components().size() == 1;
- }
-
- @Override
- public final String toString() {
- return components().stream().map(TypeElement::getQualifiedName).collect(joining(" → "));
- }
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object obj);
-}
diff --git a/java/dagger/model/DependencyRequest.java b/java/dagger/model/DependencyRequest.java
deleted file mode 100644
index 607b5ec..0000000
--- a/java/dagger/model/DependencyRequest.java
+++ /dev/null
@@ -1,77 +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.model;
-
-import com.google.auto.value.AutoValue;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.Provides;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-
-/**
- * Represents a request for a {@link Key} at an injection point. For example, parameters to {@link
- * Inject} constructors, {@link Provides} methods, and component methods are all dependency
- * requests.
- *
- * <p id="synthetic">A dependency request is considered to be <em>synthetic</em> if it does not have
- * an {@link Element} in code that requests the key directly. For example, an {@link
- * java.util.concurrent.Executor} is required for all {@code @Produces} methods to run
- * asynchronously even though it is not directly specified as a parameter to the binding method.
- */
-@AutoValue
-public abstract class DependencyRequest {
- /** The kind of this request. */
- public abstract RequestKind kind();
-
- /** The key of this request. */
- public abstract Key key();
-
- /**
- * The element that declares this dependency request. Absent for <a href="#synthetic">synthetic
- * </a> requests.
- */
- public abstract Optional<Element> requestElement();
-
- /**
- * Returns {@code true} if this request allows null objects. A request is nullable if it is
- * has an annotation with "Nullable" as its simple name.
- */
- public abstract boolean isNullable();
-
- /** Returns a new builder of dependency requests. */
- public static DependencyRequest.Builder builder() {
- return new AutoValue_DependencyRequest.Builder().isNullable(false);
- }
-
- /** A builder of {@link DependencyRequest}s. */
- @CanIgnoreReturnValue
- @AutoValue.Builder
- public abstract static class Builder {
- public abstract Builder kind(RequestKind kind);
-
- public abstract Builder key(Key key);
-
- public abstract Builder requestElement(Element element);
-
- public abstract Builder isNullable(boolean isNullable);
-
- @CheckReturnValue
- public abstract DependencyRequest build();
- }
-}
diff --git a/java/dagger/model/Key.java b/java/dagger/model/Key.java
deleted file mode 100644
index 03dd41c..0000000
--- a/java/dagger/model/Key.java
+++ /dev/null
@@ -1,286 +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.model;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.stream.Collectors.joining;
-
-import com.google.auto.common.AnnotationMirrors;
-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.base.Equivalence.Wrapper;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
-import com.squareup.javapoet.CodeBlock;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-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;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-
-/**
- * A {@linkplain TypeMirror type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
- * is the lookup key for a binding.
- */
-@AutoValue
-public abstract class Key {
- /**
- * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
- * for the type of this key.
- */
- public final Optional<AnnotationMirror> qualifier() {
- return wrappedQualifier().map(Wrapper::get);
- }
-
- /**
- * The type represented by this key.
- */
- public final TypeMirror type() {
- return wrappedType().get();
- }
-
- /**
- * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
- * for the type of this key.
- *
- * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented
- * to represent logical equality, so {@link AnnotationMirrors#equivalence()}
- * provides this facility.
- */
- abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier();
-
- /**
- * The type represented by this key.
- *
- * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent
- * logical equality, so {@link MoreTypes#equivalence()} wraps this type.
- */
- abstract Equivalence.Wrapper<TypeMirror> wrappedType();
-
- /**
- * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
- * #qualifier()}.
- *
- * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
- * contributions to that map or set using keys that identify those multibinding contributions.
- *
- * <p>Absent except for multibinding contributions.
- */
- public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
-
- /** Returns a {@link Builder} that inherits the properties of this key. */
- public abstract Builder toBuilder();
-
- // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
- // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
- // Keys
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object o);
-
- /**
- * Returns a String rendering of an {@link AnnotationMirror} that includes attributes in the order
- * defined in the annotation type. This will produce the same output for {@linkplain
- * AnnotationMirrors#equivalence() equal} {@link AnnotationMirror}s even if default values are
- * omitted or their attributes were written in different orders, e.g. {@code @A(b = "b", c = "c")}
- * and {@code @A(c = "c", b = "b", attributeWithDefaultValue = "default value")}.
- */
- // TODO(ronshapiro): move this to auto-common
- private static String stableAnnotationMirrorToString(AnnotationMirror qualifier) {
- StringBuilder builder = new StringBuilder("@").append(qualifier.getAnnotationType());
- ImmutableMap<ExecutableElement, AnnotationValue> elementValues =
- AnnotationMirrors.getAnnotationValuesWithDefaults(qualifier);
- if (!elementValues.isEmpty()) {
- ImmutableMap.Builder<String, String> namedValuesBuilder = ImmutableMap.builder();
- elementValues.forEach(
- (key, value) ->
- namedValuesBuilder.put(
- key.getSimpleName().toString(), stableAnnotationValueToString(value)));
- ImmutableMap<String, String> namedValues = namedValuesBuilder.build();
- builder.append('(');
- if (namedValues.size() == 1 && namedValues.containsKey("value")) {
- // Omit "value ="
- builder.append(namedValues.get("value"));
- } else {
- builder.append(Joiner.on(", ").withKeyValueSeparator("=").join(namedValues));
- }
- builder.append(')');
- }
- return builder.toString();
- }
-
- private static String stableAnnotationValueToString(AnnotationValue annotationValue) {
- return annotationValue.accept(
- new SimpleAnnotationValueVisitor8<String, Void>() {
- @Override
- protected String defaultAction(Object value, Void ignore) {
- return value.toString();
- }
-
- @Override
- public String visitString(String value, Void ignore) {
- return CodeBlock.of("$S", value).toString();
- }
-
- @Override
- public String visitAnnotation(AnnotationMirror value, Void ignore) {
- return stableAnnotationMirrorToString(value);
- }
-
- @Override
- public String visitArray(List<? extends AnnotationValue> value, Void ignore) {
- return value.stream()
- .map(Key::stableAnnotationValueToString)
- .collect(joining(", ", "{", "}"));
- }
- },
- null);
- }
-
- @Override
- public final String toString() {
- return Joiner.on(' ')
- .skipNulls()
- .join(
- qualifier().map(Key::stableAnnotationMirrorToString).orElse(null),
- type(),
- multibindingContributionIdentifier().orElse(null));
- }
-
- /** Returns a builder for {@link Key}s. */
- public static Builder builder(TypeMirror type) {
- return new AutoValue_Key.Builder().type(type);
- }
-
- /** A builder for {@link Key}s. */
- @CanIgnoreReturnValue
- @AutoValue.Builder
- public abstract static class Builder {
- abstract Builder wrappedType(Equivalence.Wrapper<TypeMirror> wrappedType);
-
- public final Builder type(TypeMirror type) {
- return wrappedType(MoreTypes.equivalence().wrap(checkNotNull(type)));
- }
-
- abstract Builder wrappedQualifier(
- Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier);
-
- abstract Builder wrappedQualifier(Equivalence.Wrapper<AnnotationMirror> wrappedQualifier);
-
- public final Builder qualifier(AnnotationMirror qualifier) {
- return wrappedQualifier(AnnotationMirrors.equivalence().wrap(checkNotNull(qualifier)));
- }
-
- public final Builder qualifier(Optional<AnnotationMirror> qualifier) {
- return wrappedQualifier(checkNotNull(qualifier).map(AnnotationMirrors.equivalence()::wrap));
- }
-
- public abstract Builder multibindingContributionIdentifier(
- Optional<MultibindingContributionIdentifier> identifier);
-
- public abstract Builder multibindingContributionIdentifier(
- MultibindingContributionIdentifier identifier);
-
- @CheckReturnValue
- public abstract Key build();
- }
-
- /**
- * An object that identifies a multibinding contribution method and the module class that
- * contributes it to the graph.
- *
- * @see #multibindingContributionIdentifier()
- */
- public static final class MultibindingContributionIdentifier {
- private final String module;
- private final String bindingElement;
-
- /**
- * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
- * It is not part of a specified API and may change at any point.
- */
- @Deprecated
- public MultibindingContributionIdentifier(
- // TODO(ronshapiro): reverse the order of these parameters
- ExecutableElement bindingMethod, TypeElement contributingModule) {
- this(
- bindingMethod.getSimpleName().toString(),
- contributingModule.getQualifiedName().toString());
- }
-
- // TODO(ronshapiro,dpb): create KeyProxies so that these constructors don't need to be public.
- @Deprecated
- public MultibindingContributionIdentifier(String bindingElement, String module) {
- this.module = module;
- this.bindingElement = bindingElement;
- }
-
- /**
- * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
- * It is not part of a specified API and may change at any point.
- */
- @Deprecated
- public String module() {
- return module;
- }
-
- /**
- * @deprecated This is only meant to be called from code in {@code dagger.internal.codegen}.
- * It is not part of a specified API and may change at any point.
- */
- @Deprecated
- public String bindingElement() {
- return bindingElement;
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned string is human-readable and distinguishes the keys in the same way as the
- * whole object.
- */
- @Override
- public String toString() {
- return String.format("%s#%s", module, bindingElement);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof MultibindingContributionIdentifier) {
- MultibindingContributionIdentifier other = (MultibindingContributionIdentifier) obj;
- return module.equals(other.module) && bindingElement.equals(other.bindingElement);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(module, bindingElement);
- }
- }
-}
diff --git a/java/dagger/model/RequestKind.java b/java/dagger/model/RequestKind.java
deleted file mode 100644
index 74a4346..0000000
--- a/java/dagger/model/RequestKind.java
+++ /dev/null
@@ -1,85 +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.model;
-
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-
-import dagger.Lazy;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-
-/**
- * Represents the different kinds of {@link javax.lang.model.type.TypeMirror types} that may be
- * requested as dependencies for the same key. For example, {@code String}, {@code
- * Provider<String>}, and {@code Lazy<String>} can all be requested if a key exists for {@code
- * String}; they have the {@link #INSTANCE}, {@link #PROVIDER}, and {@link #LAZY} request kinds,
- * respectively.
- */
-public enum RequestKind {
- /** A default request for an instance. E.g.: {@code FooType} */
- INSTANCE,
-
- /** A request for a {@link Provider}. E.g.: {@code Provider<FooType>} */
- PROVIDER,
-
- /** A request for a {@link Lazy}. E.g.: {@code Lazy<FooType>} */
- LAZY,
-
- /** A request for a {@link Provider} of a {@link Lazy}. E.g.: {@code Provider<Lazy<FooType>>} */
- PROVIDER_OF_LAZY,
-
- /**
- * A request for a members injection. E.g. {@code void injectMembers(FooType);}. Can only be
- * requested by component interfaces.
- */
- MEMBERS_INJECTION,
-
- /** A request for a {@link Producer}. E.g.: {@code Producer<FooType>} */
- PRODUCER,
-
- /** A request for a {@link Produced}. E.g.: {@code Produced<FooType>} */
- PRODUCED,
-
- /**
- * A request for a {@link com.google.common.util.concurrent.ListenableFuture}. E.g.: {@code
- * ListenableFuture<FooType>}. These can only be requested by component interfaces.
- */
- FUTURE,
- ;
-
- /** Returns a string that represents requests of this kind for a key. */
- public String format(Key key) {
- switch (this) {
- case INSTANCE:
- return key.toString();
-
- case PROVIDER_OF_LAZY:
- return String.format("Provider<Lazy<%s>>", key);
-
- case MEMBERS_INJECTION:
- return String.format("injectMembers(%s)", key);
-
- case FUTURE:
- return String.format("ListenableFuture<%s>", key);
-
- default:
- return String.format("%s<%s>", UPPER_UNDERSCORE.to(UPPER_CAMEL, name()), key);
- }
- }
-}
diff --git a/java/dagger/model/Scope.java b/java/dagger/model/Scope.java
deleted file mode 100644
index f48fa16..0000000
--- a/java/dagger/model/Scope.java
+++ /dev/null
@@ -1,96 +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.model;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.AnnotationMirrors;
-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 dagger.Reusable;
-import dagger.producers.ProductionScope;
-import java.lang.annotation.Annotation;
-import javax.inject.Singleton;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.TypeElement;
-
-/** A representation of a {@link javax.inject.Scope}. */
-@AutoValue
-// TODO(ronshapiro): point to SimpleAnnotationMirror
-public abstract class Scope {
- abstract Equivalence.Wrapper<AnnotationMirror> wrappedScopeAnnotation();
-
- /** The {@link AnnotationMirror} that represents the scope annotation. */
- public final AnnotationMirror scopeAnnotation() {
- return wrappedScopeAnnotation().get();
- }
-
- /** The scope annotation element. */
- public final TypeElement scopeAnnotationElement() {
- return MoreTypes.asTypeElement(scopeAnnotation().getAnnotationType());
- }
-
- /**
- * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
- */
- public static Scope scope(AnnotationMirror scopeAnnotation) {
- checkArgument(isScope(scopeAnnotation));
- return new AutoValue_Scope(AnnotationMirrors.equivalence().wrap(scopeAnnotation));
- }
-
- /**
- * Returns {@code true} if {@link #scopeAnnotation()} is a {@link javax.inject.Scope} annotation.
- */
- public static boolean isScope(AnnotationMirror scopeAnnotation) {
- return isScope(MoreElements.asType(scopeAnnotation.getAnnotationType().asElement()));
- }
-
- /**
- * Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
- */
- public static boolean isScope(TypeElement scopeAnnotationType) {
- return isAnnotationPresent(scopeAnnotationType, javax.inject.Scope.class);
- }
-
- /** Returns {@code true} if this scope is the {@link Singleton @Singleton} scope. */
- public final boolean isSingleton() {
- return isScope(Singleton.class);
- }
-
- /** Returns {@code true} if this scope is the {@link Reusable @Reusable} scope. */
- public final boolean isReusable() {
- return isScope(Reusable.class);
- }
-
- /** Returns {@code true} if this scope is the {@link ProductionScope @ProductionScope} scope. */
- public final boolean isProductionScope() {
- return isScope(ProductionScope.class);
- }
-
- private boolean isScope(Class<? extends Annotation> annotation) {
- return scopeAnnotationElement().getQualifiedName().contentEquals(annotation.getCanonicalName());
- }
-
- /** Returns a debug representation of the scope. */
- @Override
- public final String toString() {
- return scopeAnnotation().toString();
- }
-}
diff --git a/java/dagger/model/package-info.java b/java/dagger/model/package-info.java
deleted file mode 100644
index 7d09114..0000000
--- a/java/dagger/model/package-info.java
+++ /dev/null
@@ -1,31 +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 package contains the APIs that are core to Dagger's internal model of bindings and the
- * binding graph. The types are shared with the Dagger processor and are exposed to clients of the
- * Dagger SPI.
- *
- * <p>Unless otherwise specified, the types/interfaces are only intended to be implemented in this
- * package (i.e. via {@code @AutoValue}) or by Dagger's processor. This applies to test code as
- * well, so if you need a fake, please file a feature request instead of implementing it yourself.
- */
-@CheckReturnValue
-@Beta
-package dagger.model;
-
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.Beta;
diff --git a/java/dagger/model/testing/BUILD b/java/dagger/model/testing/BUILD
deleted file mode 100644
index a9d5f19..0000000
--- a/java/dagger/model/testing/BUILD
+++ /dev/null
@@ -1,39 +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.
-
-# Description:
-# Test utilities for the Dagger model
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-
-java_library(
- name = "testing",
- testonly = 1,
- srcs = glob(["*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "//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
deleted file mode 100644
index dc17c1d..0000000
--- a/java/dagger/model/testing/BindingGraphSubject.java
+++ /dev/null
@@ -1,150 +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.model.testing;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.google.common.truth.Truth.assertAbout;
-import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.truth.FailureMetadata;
-import com.google.common.truth.Subject;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import javax.lang.model.type.TypeMirror;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/** A Truth subject for making assertions on a {@link BindingGraph}. */
-public final class BindingGraphSubject extends Subject<BindingGraphSubject, BindingGraph> {
-
- /** Starts a fluent assertion about a {@link BindingGraph}. */
- public static BindingGraphSubject assertThat(BindingGraph bindingGraph) {
- return assertAbout(BindingGraphSubject::new).that(bindingGraph);
- }
-
- private final BindingGraph actual;
-
- private BindingGraphSubject(FailureMetadata metadata, @NullableDecl BindingGraph actual) {
- super(metadata, actual);
- this.actual = actual;
- }
-
- /**
- * Asserts that the graph has at least one binding with an unqualified key.
- *
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public void hasBindingWithKey(String type) {
- bindingWithKey(type);
- }
-
- /**
- * Asserts that the graph has at least one binding with a qualified key.
- *
- * @param qualifier the canonical string form of the qualifier, as returned by {@link
- * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public void hasBindingWithKey(String qualifier, String type) {
- bindingWithKey(qualifier, type);
- }
-
- /**
- * Returns a subject for testing the binding for an unqualified key.
- *
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public BindingSubject bindingWithKey(String type) {
- return bindingWithKeyString(keyString(type));
- }
-
- /**
- * Returns a subject for testing the binding for a qualified key.
- *
- * @param qualifier the canonical string form of the qualifier, as returned by {@link
- * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public BindingSubject bindingWithKey(String qualifier, String type) {
- return bindingWithKeyString(keyString(qualifier, type));
- }
-
- private BindingSubject bindingWithKeyString(String keyString) {
- ImmutableSet<Binding> bindings = getBindingNodes(keyString);
- // TODO(dpb): Handle multiple bindings for the same key.
- check("bindingsWithKey(%s)", keyString).that(bindings).hasSize(1);
- return check("bindingWithKey(%s)", keyString)
- .about(BindingSubject::new)
- .that(getOnlyElement(bindings));
- }
-
- private ImmutableSet<Binding> getBindingNodes(String keyString) {
- return actual.bindings().stream()
- .filter(binding -> binding.key().toString().equals(keyString))
- .collect(toImmutableSet());
- }
-
- private static String keyString(String type) {
- return type;
- }
-
- private static String keyString(String qualifier, String type) {
- return String.format("%s %s", qualifier, type);
- }
-
- /** A Truth subject for a {@link Binding}. */
- public final class BindingSubject extends Subject<BindingSubject, Binding> {
-
- private final Binding actual;
-
- BindingSubject(FailureMetadata metadata, @NullableDecl Binding actual) {
- super(metadata, actual);
- this.actual = actual;
- }
-
- /**
- * Asserts that the binding depends on a binding with an unqualified key.
- *
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public void dependsOnBindingWithKey(String type) {
- dependsOnBindingWithKeyString(keyString(type));
- }
-
- /**
- * Asserts that the binding depends on a binding with a qualified key.
- *
- * @param qualifier the canonical string form of the qualifier, as returned by {@link
- * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()}
- * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
- */
- public void dependsOnBindingWithKey(String qualifier, String type) {
- dependsOnBindingWithKeyString(keyString(qualifier, type));
- }
-
- private void dependsOnBindingWithKeyString(String keyString) {
- if (actualBindingGraph().requestedBindings(actual).stream()
- .noneMatch(binding -> binding.key().toString().equals(keyString))) {
- failWithActual("expected to depend on binding with key", keyString);
- }
- }
-
- private BindingGraph actualBindingGraph() {
- return BindingGraphSubject.this.actual;
- }
- }
-}
diff --git a/java/dagger/multibindings/ClassKey.java b/java/dagger/multibindings/ClassKey.java
deleted file mode 100644
index ac25545..0000000
--- a/java/dagger/multibindings/ClassKey.java
+++ /dev/null
@@ -1,39 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.MapKey;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * A {@link MapKey} annotation for maps with {@code Class<?>} keys.
- *
- * <p>If your map's keys can be constrained, consider using a custom annotation instead, with a
- * member whose type is {@code Class<? extends Something>}.
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-@MapKey
-public @interface ClassKey {
- Class<?> value();
-}
diff --git a/java/dagger/multibindings/ElementsIntoSet.java b/java/dagger/multibindings/ElementsIntoSet.java
deleted file mode 100644
index 5ed68c6..0000000
--- a/java/dagger/multibindings/ElementsIntoSet.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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * The method's return type is {@code Set<T>} and all values are contributed to the set. The {@code
- * Set<T>} produced from the accumulation of values will be immutable. An example use is to provide
- * a default empty set binding, which is otherwise not possible using {@link IntoSet}.
- *
- * @see <a href="https://dagger.dev/multibindings#set-multibindings">Set multibinding</a>
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-public @interface ElementsIntoSet {}
diff --git a/java/dagger/multibindings/IntKey.java b/java/dagger/multibindings/IntKey.java
deleted file mode 100644
index 55e79a1..0000000
--- a/java/dagger/multibindings/IntKey.java
+++ /dev/null
@@ -1,34 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.MapKey;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/** A {@link MapKey} annotation for maps with {@code int} keys. */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-@MapKey
-public @interface IntKey {
- int value();
-}
diff --git a/java/dagger/multibindings/IntoMap.java b/java/dagger/multibindings/IntoMap.java
deleted file mode 100644
index d760229..0000000
--- a/java/dagger/multibindings/IntoMap.java
+++ /dev/null
@@ -1,37 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * The method's return type forms the type argument for the value of a {@code Map<K, Provider<V>>},
- * and the combination of the annotated key and the returned value is contributed to the map as a
- * key/value pair. The {@code Map<K, Provider<V>>} produced from the accumulation of values will be
- * immutable.
- *
- * @see <a href="https://dagger.dev/multibindings#map-multibindings">Map multibinding</a>
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-public @interface IntoMap {}
diff --git a/java/dagger/multibindings/IntoSet.java b/java/dagger/multibindings/IntoSet.java
deleted file mode 100644
index b4fdcc4..0000000
--- a/java/dagger/multibindings/IntoSet.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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * The method's return type forms the generic type argument of a {@code Set<T>}, and the returned
- * value is contributed to the set. The object graph will pass dependencies to the method as
- * parameters. The {@code Set<T>} produced from the accumulation of values will be immutable.
- *
- * @see <a href="https://dagger.dev/multibindings#set-multibindings">Set multibinding</a>
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-public @interface IntoSet {}
diff --git a/java/dagger/multibindings/LongKey.java b/java/dagger/multibindings/LongKey.java
deleted file mode 100644
index 71d0fe1..0000000
--- a/java/dagger/multibindings/LongKey.java
+++ /dev/null
@@ -1,34 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.MapKey;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/** A {@link MapKey} annotation for maps with {@code long} keys. */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-@MapKey
-public @interface LongKey {
- long value();
-}
diff --git a/java/dagger/multibindings/Multibinds.java b/java/dagger/multibindings/Multibinds.java
deleted file mode 100644
index e37b39e..0000000
--- a/java/dagger/multibindings/Multibinds.java
+++ /dev/null
@@ -1,56 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates abstract module methods that declare multibindings.
- *
- * <p>You can declare that a multibound set or map is bound by annotating an abstract module method
- * that returns the set or map you want to declare with {@code @Multibinds}.
- *
- * <p>You do not have to use {@code @Multibinds} for sets or maps that have at least one
- * contribution, but you do have to declare them if they may be empty.
- *
- * <pre><code>
- * {@literal @Module} abstract class MyModule {
- * {@literal @Multibinds abstract Set<Foo> aSet();}
- * {@literal @Multibinds abstract @MyQualifier Set<Foo> aQualifiedSet();}
- * {@literal @Multibinds abstract Map<String, Foo> aMap();}
- * {@literal @Multibinds abstract @MyQualifier Map<String, Foo> aQualifiedMap();}
- *
- * {@literal @Provides}
- * {@literal static Object usesMultibindings(Set<Foo> set, @MyQualifier Map<String, Foo> map}) {
- * return …
- * }
- * }</code></pre>
- *
- * <p>A given set or map multibinding can be declared any number of times without error. Dagger
- * never implements or calls any {@code @Multibinds} methods.
- *
- * @see <a href="https://dagger.dev/multibindings">Multibindings</a>
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-public @interface Multibinds {}
diff --git a/java/dagger/multibindings/StringKey.java b/java/dagger/multibindings/StringKey.java
deleted file mode 100644
index 5dad8e3..0000000
--- a/java/dagger/multibindings/StringKey.java
+++ /dev/null
@@ -1,34 +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.multibindings;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.MapKey;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/** A {@link MapKey} annotation for maps with {@link String} keys. */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-@MapKey
-public @interface StringKey {
- String value();
-}
diff --git a/java/dagger/multibindings/package-info.java b/java/dagger/multibindings/package-info.java
deleted file mode 100644
index d6fe1e1..0000000
--- a/java/dagger/multibindings/package-info.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.
- */
-
-/**
- * This package contains the API by which Dagger allows you to bind several objects into a
- * collection that can be injected without depending directly on each of the individual bindings.
- *
- * @see <a href="https://dagger.dev/multibindings">Multibindings in the Dagger User's Guide</a>
- */
-package dagger.multibindings;
diff --git a/java/dagger/package-info.java b/java/dagger/package-info.java
deleted file mode 100644
index b680a85..0000000
--- a/java/dagger/package-info.java
+++ /dev/null
@@ -1,33 +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.
- */
-
-/**
- * This package contains the public API for the <a href="https://dagger.dev/">Dagger 2</a> dependency
- * injection framework. By building upon <a href="https://jcp.org/en/jsr/detail?id=330">JSR 330</a>,
- * Dagger 2 provides an annotation-driven API for dependency injection whose implementation is
- * entirely generated at compile time by <a
- * href="http://en.wikipedia.org/wiki/Java_annotation#Processing">annotation processors</a>.
- *
- * <p>The entry point into the API is the {@link Component}, which annotates abstract types for
- * Dagger 2 to implement. The dependency graph is configured using annotations such as {@link
- * Module}, {@link Provides} and {@link javax.inject.Inject}.
- *
- * <p>{@code dagger.internal.codegen.ComponentProcessor} is the processor responsible for generating
- * the implementation. Dagger uses the annotation procesor {@linkplain java.util.ServiceLoader
- * service loader} to automatically configure the processor, so explict build configuration
- * shouldn't be necessary.
- */
-package dagger;
diff --git a/java/dagger/producers/BUILD b/java/dagger/producers/BUILD
deleted file mode 100644
index ad065a1..0000000
--- a/java/dagger/producers/BUILD
+++ /dev/null
@@ -1,74 +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:
-# An asynchronous dependency injection system that extends JSR-330.
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
- "SOURCE_7_TARGET_7",
-)
-load("//tools:maven.bzl", "pom_file", "POM_VERSION")
-
-# Work around b/70476182 which prevents Kythe from connecting :producers to the .java files it
-# contains.
-SRCS = glob(["**/*.java"])
-
-filegroup(
- name = "producers-srcs",
- srcs = SRCS,
-)
-
-java_library(
- name = "producers",
- srcs = SRCS,
- javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- tags = ["maven_coordinates=com.google.dagger:dagger-producers:" + POM_VERSION],
- exports = [
- # 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",
- "@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",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-producers",
- artifact_name = "Dagger Producers",
- 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",
- ],
- root_packages = ["dagger.producers"],
- deps = [":producers"],
-)
diff --git a/java/dagger/producers/CancellationPolicy.java b/java/dagger/producers/CancellationPolicy.java
deleted file mode 100644
index 70f4a43..0000000
--- a/java/dagger/producers/CancellationPolicy.java
+++ /dev/null
@@ -1,66 +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.producers;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a production component or subcomponent to specify its policy when a child component is
- * cancelled.
- *
- * <p>When a future returned from an entry point on a production component is cancelled, the
- * component is cancelled: all producers in the component (including those for other entry points)
- * are cancelled.
- *
- * <p>When a child component is cancelled, its parent component <i>is not</i> cancelled unless the
- * parent component is annotated with {@code @CancellationPolicy(fromSubcomponents = PROPAGATE)}. If
- * that parent component has a parent (the grandparent of the cancelled child component), it will
- * not be cancelled unless it also has a {@code @CancellationPolicy} annotation allowing
- * cancellation to propagate to it from subcomponents.
- */
-@Documented
-@Target(TYPE)
-@Retention(CLASS)
-@Beta
-public @interface CancellationPolicy {
- /**
- * Defines whether the annotated production component is cancelled when a child component is
- * cancelled.
- *
- * <p>The default, if no cancellation policy annotation is provided, is {@link
- * Propagation#IGNORE}.
- */
- Propagation fromSubcomponents();
-
- /**
- * Enumeration of the options for what happens to a parent component when one of its child
- * components is cancelled.
- */
- enum Propagation {
- /** Cancel the annotated component when a child component is cancelled. */
- PROPAGATE,
-
- /** Do not cancel the annotated component when a child component is cancelled. */
- IGNORE
- }
-}
diff --git a/java/dagger/producers/Produced.java b/java/dagger/producers/Produced.java
deleted file mode 100644
index 5b7847f..0000000
--- a/java/dagger/producers/Produced.java
+++ /dev/null
@@ -1,153 +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.producers;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Objects;
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.Beta;
-import java.util.concurrent.ExecutionException;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/**
- * An interface that represents the result of a {@linkplain Producer production} of type {@code T},
- * or an exception that was thrown during that production. For any type {@code T} that can be
- * injected, you can also inject {@code Produced<T>}, which enables handling of any exceptions that
- * were thrown during the production of {@code T}.
- *
- * <p>For example: <pre><code>
- * {@literal @}Produces Html getResponse(
- * UserInfo criticalInfo, {@literal Produced<ExtraInfo>} noncriticalInfo) {
- * try {
- * return new Html(criticalInfo, noncriticalInfo.get());
- * } catch (ExecutionException e) {
- * logger.warning(e, "Noncritical info");
- * return new Html(criticalInfo);
- * }
- * }
- * </code></pre>
- *
- * @since 2.0
- */
-@Beta
-@CheckReturnValue
-public abstract class Produced<T> {
- /**
- * Returns the result of a production.
- *
- * @throws ExecutionException if the production threw an exception
- */
- public abstract T get() throws ExecutionException;
-
- /**
- * Two {@code Produced} objects compare equal if both are successful with equal values, or both
- * are failed with equal exceptions.
- */
- @Override
- public abstract boolean equals(Object o);
-
- /** Returns an appropriate hash code to match {@link #equals(Object)}. */
- @Override
- public abstract int hashCode();
-
- /** Returns a successful {@code Produced}, whose {@link #get} will return the given value. */
- public static <T> Produced<T> successful(@NullableDecl T value) {
- return new Successful<T>(value);
- }
-
- /**
- * Returns a failed {@code Produced}, whose {@link #get} will throw an
- * {@code ExecutionException} with the given cause.
- */
- public static <T> Produced<T> failed(Throwable throwable) {
- return new Failed<T>(checkNotNull(throwable));
- }
-
- private static final class Successful<T> extends Produced<T> {
- @NullableDecl private final T value;
-
- private Successful(@NullableDecl T value) {
- this.value = value;
- }
-
- @Override
- @NullableDecl
- public T get() {
- return value;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (o instanceof Successful) {
- Successful<?> that = (Successful<?>) o;
- return Objects.equal(this.value, that.value);
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return value == null ? 0 : value.hashCode();
- }
-
- @Override
- public String toString() {
- return "Produced[" + value + "]";
- }
- }
-
- private static final class Failed<T> extends Produced<T> {
- private final Throwable throwable;
-
- private Failed(Throwable throwable) {
- this.throwable = checkNotNull(throwable);
- }
-
- @Override
- public T get() throws ExecutionException {
- throw new ExecutionException(throwable);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (o instanceof Failed) {
- Failed<?> that = (Failed<?>) o;
- return this.throwable.equals(that.throwable);
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return throwable.hashCode();
- }
-
- @Override
- public String toString() {
- return "Produced[failed with " + throwable.getClass().getCanonicalName() + "]";
- }
- }
-
- private Produced() {}
-}
diff --git a/java/dagger/producers/Producer.java b/java/dagger/producers/Producer.java
deleted file mode 100644
index 8485f81..0000000
--- a/java/dagger/producers/Producer.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.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.Beta;
-
-/**
- * An interface that represents the production of a type {@code T}. You can also inject
- * {@code Producer<T>} instead of {@code T}, which will delay the execution of any code that
- * produces the {@code T} until {@link #get} is called.
- *
- * <p>For example, you might inject {@code Producer} to lazily choose between several different
- * implementations of some type: <pre><code>
- * {@literal @Produces ListenableFuture<Heater>} getHeater(
- * HeaterFlag flag,
- * {@literal @Electric Producer<Heater>} electricHeater,
- * {@literal @Gas Producer<Heater>} gasHeater) {
- * return flag.useElectricHeater() ? electricHeater.get() : gasHeater.get();
- * }
- * </code></pre>
- *
- * <p>Here is a complete example that demonstrates how calling {@code get()} will cause each
- * method to be executed: <pre><code>
- *
- * {@literal @}ProducerModule
- * final class MyModule {
- * {@literal @Produces ListenableFuture<A>} a() {
- * System.out.println("a");
- * return Futures.immediateFuture(new A());
- * }
- *
- * {@literal @Produces ListenableFuture<B>} b(A a) {
- * System.out.println("b");
- * return Futures.immediateFuture(new B(a));
- * }
- *
- * {@literal @Produces ListenableFuture<C>} c(B b) {
- * System.out.println("c");
- * return Futures.immediateFuture(new C(b));
- * }
- *
- * {@literal @Produces @Delayed ListenableFuture<C>} delayedC(A a, {@literal Producer<C>} c) {
- * System.out.println("delayed c");
- * return c.get();
- * }
- * }
- *
- * {@literal @}ProductionComponent(modules = MyModule.class)
- * interface MyComponent {
- * {@literal @Delayed ListenableFuture<C>} delayedC();
- * }
- * </code></pre>
- * Suppose we instantiate the generated implementation of this component and call
- * {@code delayedC()}: <pre><code>
- * MyComponent component = DaggerMyComponent
- * .builder()
- * .executor(MoreExecutors.directExecutor())
- * .build();
- * System.out.println("Constructed component");
- * {@literal ListenableFuture<C>} cFuture = component.delayedC();
- * System.out.println("Retrieved future");
- * C c = cFuture.get();
- * System.out.println("Retrieved c");
- * </code></pre>
- * Here, we're using {@code MoreExecutors.directExecutor} in order to illustrate how each call
- * directly causes code to execute. The above code will print: <pre><code>
- * Constructed component
- * a
- * delayed c
- * b
- * c
- * Retrieved future
- * Retrieved c
- * </code></pre>
- *
- * @since 2.0
- */
-@Beta
-public interface Producer<T> {
- /**
- * Returns a future representing a running task that produces a value. Calling this method will
- * trigger the submission of this task to the executor, if it has not already been triggered. In
- * order to trigger this task's submission, the transitive dependencies required to produce the
- * {@code T} will be submitted to the executor, as their dependencies become available.
- *
- * <p>If the key is bound to a {@link Produces} method, then calling this method multiple times
- * will return the same future.
- */
- @CheckReturnValue
- ListenableFuture<T> get();
-}
diff --git a/java/dagger/producers/ProducerModule.java b/java/dagger/producers/ProducerModule.java
deleted file mode 100644
index e14d450..0000000
--- a/java/dagger/producers/ProducerModule.java
+++ /dev/null
@@ -1,53 +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.producers;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.Module;
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a class that contributes {@link Produces} bindings to the production component.
- *
- * @since 2.0
- */
-@Documented
-@Target(TYPE)
-@Retention(RUNTIME)
-@Beta
-public @interface ProducerModule {
- /**
- * Additional {@code @ProducerModule}- or {@link Module}-annotated classes from which this module
- * is composed. The de-duplicated contributions of the modules in {@code includes}, and of their
- * inclusions recursively, are all contributed to the object graph.
- */
- Class<?>[] includes() default {};
-
- /**
- * Any {@link dagger.Subcomponent}- or {@link ProductionSubcomponent}-annotated classes which
- * should be children of the component in which this module is installed. A subcomponent may be
- * listed in more than one module in a component.
- *
- * @since 2.7
- */
- Class<?>[] subcomponents() default {};
-}
diff --git a/java/dagger/producers/Producers.java b/java/dagger/producers/Producers.java
deleted file mode 100644
index 1c8da03..0000000
--- a/java/dagger/producers/Producers.java
+++ /dev/null
@@ -1,66 +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.producers;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.Beta;
-import dagger.producers.internal.CancellableProducer;
-import dagger.producers.internal.CancellationListener;
-
-/** Utility methods to create {@link Producer}s. */
-@Beta
-public final class Producers {
- /** Returns a producer that succeeds with the given value. */
- public static <T> Producer<T> immediateProducer(final T value) {
- return new ImmediateProducer<>(Futures.immediateFuture(value));
- }
-
- /** Returns a producer that fails with the given exception. */
- public static <T> Producer<T> immediateFailedProducer(final Throwable throwable) {
- return new ImmediateProducer<>(Futures.<T>immediateFailedFuture(throwable));
- }
-
- /** A {@link CancellableProducer} with an immediate result. */
- private static final class ImmediateProducer<T> implements CancellableProducer<T> {
- private final ListenableFuture<T> future;
-
- ImmediateProducer(ListenableFuture<T> future) {
- this.future = future;
- }
-
- @Override
- public ListenableFuture<T> get() {
- return future;
- }
-
- @Override
- public void cancel(boolean mayInterruptIfRunning) {}
-
- @Override
- public Producer<T> newDependencyView() {
- return this;
- }
-
- @Override
- public Producer<T> newEntryPointView(CancellationListener cancellationListener) {
- return this;
- }
- }
-
- private Producers() {}
-}
diff --git a/java/dagger/producers/Produces.java b/java/dagger/producers/Produces.java
deleted file mode 100644
index df859ad..0000000
--- a/java/dagger/producers/Produces.java
+++ /dev/null
@@ -1,40 +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.producers;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates methods of a producer module to create a production binding. If the method returns a
- * {@link com.google.common.util.concurrent.ListenableFuture} or {@link
- * com.google.common.util.concurrent.FluentFuture}, then the parameter type of the future is bound
- * to the value that the future produces; otherwise, the return type is bound to the returned value.
- * The production component will pass dependencies to the method as parameters.
- *
- * @since 2.0
- */
-@Documented
-@Target(METHOD)
-@Retention(RUNTIME)
-@Beta
-public @interface Produces {}
diff --git a/java/dagger/producers/Production.java b/java/dagger/producers/Production.java
deleted file mode 100644
index 563fc16..0000000
--- a/java/dagger/producers/Production.java
+++ /dev/null
@@ -1,37 +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.producers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * Qualifies a type that will be provided to the framework for use internally.
- *
- * <p>The only type that may be so qualified is {@link java.util.concurrent.Executor}. In this case,
- * the resulting executor is used to schedule {@linkplain Produces producer methods} in a
- * {@link ProductionComponent} or {@link ProductionSubcomponent}.
- */
-@Documented
-@Retention(RUNTIME)
-@Qualifier
-@Beta
-public @interface Production {}
diff --git a/java/dagger/producers/ProductionComponent.java b/java/dagger/producers/ProductionComponent.java
deleted file mode 100644
index a0337cf..0000000
--- a/java/dagger/producers/ProductionComponent.java
+++ /dev/null
@@ -1,121 +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.producers;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-
-/**
- * Annotates an interface or abstract class for which a fully-formed, dependency-injected
- * implementation is to be generated from a set of {@linkplain #modules modules}. The generated
- * class will have the name of the type annotated with {@code @ProductionComponent} prepended with
- * {@code Dagger}. For example, {@code @ProductionComponent interface MyComponent {...}} will
- * produce an implementation named {@code DaggerMyComponent}.
- *
- * <p>Each {@link Produces} method that contributes to the component will be called at most once per
- * component instance, no matter how many times that binding is used as a dependency. TODO(beder):
- * Decide on how scope works for producers.
- *
- * <h2>Component methods</h2>
- *
- * <p>Every type annotated with {@code @ProductionComponent} must contain at least one abstract
- * component method. Component methods must represent {@linkplain Producer production}.
- *
- * <p>Production methods have no arguments and return either a {@link ListenableFuture} or {@link
- * Producer} of a type that is {@link Inject injected}, {@link Provides provided}, or {@link
- * Produces produced}. Each may have a {@link Qualifier} annotation as well. The following are all
- * valid production method declarations:
- *
- * <pre><code>
- * {@literal ListenableFuture<SomeType>} getSomeType();
- * {@literal Producer<Set<SomeType>>} getSomeTypes();
- * {@literal @Response ListenableFuture<Html>} getResponse();
- * </code></pre>
- *
- * <h2>Exceptions</h2>
- *
- * <p>When a producer throws an exception, the exception will be propagated to its downstream
- * producers in the following way: if the downstream producer injects a type {@code T}, then that
- * downstream producer will be skipped, and the exception propagated to its downstream producers;
- * and if the downstream producer injects a {@code Produced<T>}, then the downstream producer will
- * be run with the exception stored in the {@code Produced<T>}.
- *
- * <p>If a non-execution exception is thrown (e.g., an {@code InterruptedException} or {@code
- * CancellationException}), then exception is handled as in {@link
- * com.google.common.util.concurrent.Futures#transform}.
- * <!-- TODO(beder): Explain this more thoroughly, and update the javadocs of those utilities. -->
- *
- * <h2>Executor</h2>
- *
- * <p>The component must include a binding for <code>{@literal @}{@link Production}
- * {@link java.util.concurrent.Executor}</code>; this binding will be called exactly once, and the
- * provided executor will be used by the framework to schedule all producer methods (for this
- * component, and any {@link ProductionSubcomponent} it may have.
- *
- * @since 2.0
- */
-@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
-@Documented
-@Target(TYPE)
-@Beta
-public @interface ProductionComponent {
- /**
- * A list of classes annotated with {@link Module} or {@link ProducerModule} whose bindings are
- * used to generate the component implementation.
- */
- Class<?>[] modules() default {};
-
- /**
- * A list of types that are to be used as component dependencies.
- */
- Class<?>[] dependencies() default {};
-
- /**
- * A builder for a production component.
- *
- * <p>This follows all the rules of {@link Component.Builder}, except it must appear in classes
- * annotated with {@link ProductionComponent} instead of {@code Component}.
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Builder {}
-
- /**
- * A factory for a production component.
- *
- * <p>This follows all the rules of {@link Component.Factory}, except it must appear in classes
- * annotated with {@link ProductionComponent} instead of {@code Component}.
- *
- * @since 2.22
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Factory {}
-}
diff --git a/java/dagger/producers/ProductionScope.java b/java/dagger/producers/ProductionScope.java
deleted file mode 100644
index 393c240..0000000
--- a/java/dagger/producers/ProductionScope.java
+++ /dev/null
@@ -1,32 +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.producers;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * A scope annotation for provision bindings that are tied to the lifetime of a
- * {@link ProductionComponent} or {@link ProductionSubcomponent}.
- */
-@Documented
-@Retention(RUNTIME)
-@Scope
-public @interface ProductionScope {}
diff --git a/java/dagger/producers/ProductionSubcomponent.java b/java/dagger/producers/ProductionSubcomponent.java
deleted file mode 100644
index 5774945..0000000
--- a/java/dagger/producers/ProductionSubcomponent.java
+++ /dev/null
@@ -1,83 +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.producers;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * A subcomponent that inherits the bindings from a parent {@link Component}, {@link Subcomponent},
- * {@link ProductionComponent}, or {@link ProductionSubcomponent}. The details of how to associate a
- * subcomponent with a parent are described in the documentation for {@link Component}.
- *
- * <p>The executor for a production subcomponent is supplied by binding
- * <code>{@literal @}Production Executor</code>, similar to {@link ProductionComponent}. Note that
- * this binding may be in an ancestor component.
- *
- * @since 2.1
- */
-@Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
-@Target(TYPE)
-@Documented
-public @interface ProductionSubcomponent {
- /**
- * A list of classes annotated with {@link Module} or {@link ProducerModule} whose bindings are
- * used to generate the subcomponent implementation. Note that through the use of
- * {@link Module#includes} or {@link ProducerModule#includes} the full set of modules used to
- * implement the subcomponent may include more modules that just those listed here.
- */
- Class<?>[] modules() default {};
-
- /**
- * A builder for a production subcomponent.
- *
- * <p>This follows all the rules of {@link Component.Builder}, except it must appear in classes
- * annotated with {@link ProductionSubcomponent} instead of {@code Component}.
- *
- * <p>If a subcomponent defines a builder, its parent component(s) will have a binding for that
- * builder type, allowing an instance or {@code Provider} of that builder to be injected or
- * returned from a method on that component like any other binding.
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Builder {}
-
- /**
- * A factory for a production subcomponent.
- *
- * <p>This follows all the rules of {@link Component.Factory}, except it must appear in classes
- * annotated with {@link ProductionSubcomponent} instead of {@code Component}.
- *
- * <p>If a subcomponent defines a factory, its parent component(s) will have a binding for that
- * factory type, allowing an instance that factory to be injected or returned from a method on
- * that component like any other binding.
- *
- * @since 2.22
- */
- @Retention(RUNTIME) // Allows runtimes to have specialized behavior interoperating with Dagger.
- @Target(TYPE)
- @Documented
- @interface Factory {}
-}
diff --git a/java/dagger/producers/internal/AbstractMapProducer.java b/java/dagger/producers/internal/AbstractMapProducer.java
deleted file mode 100644
index c60f0cb..0000000
--- a/java/dagger/producers/internal/AbstractMapProducer.java
+++ /dev/null
@@ -1,93 +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.producers.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.producers.internal.Producers.producerFromProvider;
-
-import com.google.common.collect.ImmutableMap;
-import dagger.producers.Producer;
-import java.util.Map;
-import javax.inject.Provider;
-
-/**
- * An {@code abstract} {@link Producer} implementation used to implement {@link Map} bindings.
- *
- * @param <K>The key type of the map that this produces
- * @param <V>The type that each contributing producer
- * @param <V2>The value type of the map that this produces. For {@link MapProducer}, {@code V} and
- * {@code V2} will be equivalent.
- */
-abstract class AbstractMapProducer<K, V, V2> extends AbstractProducer<Map<K, V2>> {
- private final ImmutableMap<K, Producer<V>> contributingMap;
-
- AbstractMapProducer(ImmutableMap<K, Producer<V>> contributingMap) {
- this.contributingMap = contributingMap;
- }
-
- /** The map of {@link Producer}s that contribute to this map binding. */
- final ImmutableMap<K, Producer<V>> contributingMap() {
- return contributingMap;
- }
-
- /** A builder for {@link AbstractMapProducer} */
- public abstract static class Builder<K, V, V2> {
- final ImmutableMap.Builder<K, Producer<V>> mapBuilder;
-
- Builder(int size) {
- mapBuilder = ImmutableMap.builderWithExpectedSize(size);
- }
-
- // Unfortunately, we cannot return a self-type here because a raw Producer type passed to one of
- // these methods affects the returned type of the method. The first put*() call erases the self
- // type to the "raw" self type, and the second erases the type to the upper bound
- // (AbstractMapProducer.Builder), which doesn't have a build() method.
- //
- // The methods are therefore not declared public so that each subtype will redeclare them and
- // expand their accessibility
-
- /** Associates {@code key} with {@code producerOfValue}. */
- Builder<K, V, V2> put(K key, Producer<V> producerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(producerOfValue, "producer of value");
- mapBuilder.put(key, producerOfValue);
- return this;
- }
-
- /** Associates {@code key} with {@code providerOfValue}. */
- Builder<K, V, V2> put(K key, Provider<V> providerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(providerOfValue, "provider of value");
- mapBuilder.put(key, producerFromProvider(providerOfValue));
- return this;
- }
-
- /** Adds contributions from a super-implementation of a component into this builder. */
- Builder<K, V, V2> putAll(Producer<Map<K, V2>> mapOfProducers) {
- if (mapOfProducers instanceof DelegateProducer) {
- @SuppressWarnings("unchecked")
- DelegateProducer<Map<K, V2>> asDelegateProducer = (DelegateProducer) mapOfProducers;
- return putAll(asDelegateProducer.getDelegate());
- }
- @SuppressWarnings("unchecked")
- AbstractMapProducer<K, V, ?> asAbstractMapProducer =
- ((AbstractMapProducer<K, V, ?>) (Producer) mapOfProducers);
- mapBuilder.putAll(asAbstractMapProducer.contributingMap);
- return this;
- }
- }
-}
diff --git a/java/dagger/producers/internal/AbstractProducer.java b/java/dagger/producers/internal/AbstractProducer.java
deleted file mode 100644
index 3dcd906..0000000
--- a/java/dagger/producers/internal/AbstractProducer.java
+++ /dev/null
@@ -1,167 +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.producers.internal;
-
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.util.concurrent.AbstractFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/** An abstract {@link Producer} implementation that memoizes the result of its compute method. */
-public abstract class AbstractProducer<T> implements CancellableProducer<T> {
- private final AtomicBoolean requested = new AtomicBoolean();
- private final NonExternallyCancellableFuture<T> future = new NonExternallyCancellableFuture<T>();
-
- protected AbstractProducer() {}
-
- /** Computes this producer's future, which is then cached in {@link #get}. */
- protected abstract ListenableFuture<T> compute();
-
- @Override
- public final ListenableFuture<T> get() {
- if (requested.compareAndSet(false, true)) {
- future.setFuture(compute());
- }
- return future;
- }
-
- @Override
- public final void cancel(boolean mayInterruptIfRunning) {
- requested.set(true); // Avoid potentially starting the task later only to cancel it immediately.
- future.doCancel(mayInterruptIfRunning);
- }
-
- @Override
- public Producer<T> newDependencyView() {
- return new NonCancellationPropagatingView();
- }
-
- @Override
- public Producer<T> newEntryPointView(CancellationListener cancellationListener) {
- NonCancellationPropagatingView result = new NonCancellationPropagatingView();
- result.addCancellationListener(cancellationListener);
- return result;
- }
-
- /**
- * A view of this producer that returns a future that can be cancelled without cancelling the
- * producer itself.
- */
- private final class NonCancellationPropagatingView implements Producer<T> {
- /**
- * An independently cancellable view of this node. Needs to be cancellable by normal future
- * cancellation so that the view at an entry point can listen for its cancellation.
- */
- private final ListenableFuture<T> viewFuture = nonCancellationPropagating(future);
-
- @SuppressWarnings("FutureReturnValueIgnored")
- @Override
- public ListenableFuture<T> get() {
- AbstractProducer.this.get(); // force compute()
- return viewFuture;
- }
-
- void addCancellationListener(final CancellationListener cancellationListener) {
- viewFuture.addListener(
- new Runnable() {
- @Override
- public void run() {
- if (viewFuture.isCancelled()) {
- boolean mayInterruptIfRunning =
- viewFuture instanceof NonCancellationPropagatingFuture
- && ((NonCancellationPropagatingFuture) viewFuture).interrupted();
- cancellationListener.onProducerFutureCancelled(mayInterruptIfRunning);
- }
- }
- },
- directExecutor());
- }
- }
-
- /** A settable future that can't be cancelled via normal future cancellation. */
- private static final class NonExternallyCancellableFuture<T> extends AbstractFuture<T> {
-
- @Override
- public boolean setFuture(ListenableFuture<? extends T> future) {
- return super.setFuture(future);
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false;
- }
-
- /** Actually cancels this future. */
- void doCancel(boolean mayInterruptIfRunning) {
- super.cancel(mayInterruptIfRunning);
- }
- }
-
- private static <T> ListenableFuture<T> nonCancellationPropagating(ListenableFuture<T> future) {
- if (future.isDone()) {
- return future;
- }
- NonCancellationPropagatingFuture<T> output = new NonCancellationPropagatingFuture<T>(future);
- future.addListener(output, directExecutor());
- return output;
- }
-
- /**
- * Equivalent to {@code Futures.nonCancellationPropagating}, but allowing us to check whether or
- * not {@code mayInterruptIfRunning} was set when cancelling it.
- */
- private static final class NonCancellationPropagatingFuture<T> extends AbstractFuture<T>
- implements Runnable {
- // TODO(cgdecker): This is copied directly from Producers.nonCancellationPropagating, but try
- // to find out why this doesn't need to be volatile.
- private ListenableFuture<T> delegate;
-
- NonCancellationPropagatingFuture(final ListenableFuture<T> delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void run() {
- // This prevents cancellation from propagating because we don't call setFuture(delegate) until
- // delegate is already done, so calling cancel() on this future won't affect it.
- ListenableFuture<T> localDelegate = delegate;
- if (localDelegate != null) {
- setFuture(localDelegate);
- }
- }
-
- @Override
- protected String pendingToString() {
- ListenableFuture<T> localDelegate = delegate;
- if (localDelegate != null) {
- return "delegate=[" + localDelegate + "]";
- }
- return null;
- }
-
- @Override
- protected void afterDone() {
- delegate = null;
- }
-
- public boolean interrupted() {
- return super.wasInterrupted();
- }
- }
-}
diff --git a/java/dagger/producers/internal/AbstractProducesMethodProducer.java b/java/dagger/producers/internal/AbstractProducesMethodProducer.java
deleted file mode 100644
index 0cf36ca..0000000
--- a/java/dagger/producers/internal/AbstractProducesMethodProducer.java
+++ /dev/null
@@ -1,100 +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.producers.internal;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.concurrent.Executor;
-import javax.inject.Provider;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/**
- * An {@link AbstractProducer} for all {@link dagger.producers.Produces} methods.
- *
- * @param <D> the type of asynchronous dependencies. These will be collected in {@link
- * #collectDependencies()} and then made available to the {@code @Produces method in} {@link
- * #callProducesMethod(Object)}. If there is only one asynchronous dependency, {@code D} can be
- * the key for that dependency. If there are multiple, they should be wrapped in a list and
- * unwrapped in {@link #callProducesMethod(Object)}.
- * @param <T> the produced type
- */
-public abstract class AbstractProducesMethodProducer<D, T> extends AbstractProducer<T>
- implements AsyncFunction<D, T>, Executor {
- private final Provider<ProductionComponentMonitor> monitorProvider;
- @NullableDecl private final ProducerToken token;
- private final Provider<Executor> executorProvider;
- private volatile ProducerMonitor monitor = null;
-
- protected AbstractProducesMethodProducer(
- Provider<ProductionComponentMonitor> monitorProvider,
- @NullableDecl ProducerToken token,
- Provider<Executor> executorProvider) {
- this.monitorProvider = checkNotNull(monitorProvider);
- this.token = token;
- this.executorProvider = checkNotNull(executorProvider);
- }
-
- @Override
- protected final ListenableFuture<T> compute() {
- monitor = monitorProvider.get().producerMonitorFor(token);
- monitor.requested();
- ListenableFuture<T> result = Futures.transformAsync(collectDependencies(), this, this);
- monitor.addCallbackTo(result);
- return result;
- }
-
- /**
- * Collects the asynchronous dependencies to be passed to {@link
- * Futures#transformAsync(ListenableFuture, AsyncFunction, Executor)}.
- */
- protected abstract ListenableFuture<D> collectDependencies();
-
- /** @deprecated this may only be called from the internal {@link #compute()} */
- @Deprecated
- @Override
- public final ListenableFuture<T> apply(D asyncDependencies) throws Exception {
- // NOTE(beder): We don't worry about catching exceptions from the monitor methods themselves
- // because we'll wrap all monitoring in non-throwing monitors before we pass them to the
- // factories.
- monitor.methodStarting();
- try {
- return callProducesMethod(asyncDependencies);
- } finally {
- monitor.methodFinished();
- }
- }
-
- /**
- * Calls the {@link dagger.producers.Produces} method. This will always be called on the {@link
- * Executor} provided to this producer.
- */
- protected abstract ListenableFuture<T> callProducesMethod(D asyncDependencies) throws Exception;
-
- /** @deprecated this may only be called from the internal {@link #compute()} */
- @Deprecated
- @Override
- public final void execute(Runnable runnable) {
- monitor.ready();
- executorProvider.get().execute(runnable);
- }
-}
diff --git a/java/dagger/producers/internal/CancellableProducer.java b/java/dagger/producers/internal/CancellableProducer.java
deleted file mode 100644
index 6a1475e..0000000
--- a/java/dagger/producers/internal/CancellableProducer.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.producers.internal;
-
-import dagger.producers.Producer;
-
-/** A {@link Producer} that can be cancelled directly even if it hasn't been started. */
-public interface CancellableProducer<T> extends Producer<T> {
-
- /**
- * Cancels this producer. If {@link #get()} has already been called, the future it returns will be
- * cancelled if possible. If not, calling {@link #get()} will return a cancelled future and will
- * not actually start the underlying operation.
- *
- * @param mayInterruptIfRunning the value that should be passed to {@code Future.cancel(boolean)}
- * for the futures for any running tasks when cancelling them
- */
- void cancel(boolean mayInterruptIfRunning);
-
- /** Returns a new view of this producer for use as a dependency of another node. */
- Producer<T> newDependencyView();
-
- /**
- * Returns a new view of this producer for use as an entry point.
- *
- * <p>When the view's future is cancelled, the given {@code cancellableListener} will be called.
- */
- Producer<T> newEntryPointView(CancellationListener cancellationListener);
-}
diff --git a/java/dagger/producers/internal/CancellationListener.java b/java/dagger/producers/internal/CancellationListener.java
deleted file mode 100644
index 182ddc6..0000000
--- a/java/dagger/producers/internal/CancellationListener.java
+++ /dev/null
@@ -1,25 +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.producers.internal;
-
-/** A listener for producer future cancellation. */
-public interface CancellationListener {
- /** Called when the future for a producer this listener has been added to is cancelled. */
- // Note that this name is intentionally a bit verbose to make it unlikely that it will conflict
- // with any user-defined methods on a component.
- void onProducerFutureCancelled(boolean mayInterruptIfRunning);
-}
diff --git a/java/dagger/producers/internal/DelegateProducer.java b/java/dagger/producers/internal/DelegateProducer.java
deleted file mode 100644
index 6cc7547..0000000
--- a/java/dagger/producers/internal/DelegateProducer.java
+++ /dev/null
@@ -1,111 +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.producers.internal;
-
-import static dagger.internal.Preconditions.checkNotNull;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.DoubleCheck;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-
-/**
- * A DelegateProducer that is used to stitch Producer indirection during initialization across
- * partial subcomponent implementations.
- */
-public final class DelegateProducer<T> implements CancellableProducer<T> {
- private CancellableProducer<T> delegate;
-
- @Override
- public ListenableFuture<T> get() {
- return delegate.get();
- }
-
- // TODO(ronshapiro): remove this once we can reasonably expect generated code is no longer using
- // this method
- @Deprecated
- public void setDelegatedProducer(Producer<T> delegate) {
- setDelegate(this, delegate);
- }
-
- /**
- * Sets {@code delegateProducer}'s delegate producer to {@code delegate}.
- *
- * <p>{@code delegateProducer} must be an instance of {@link DelegateProducer}, otherwise this
- * method will throw a {@link ClassCastException}.
- */
- public static <T> void setDelegate(Producer<T> delegateProducer, Producer<T> delegate) {
- checkNotNull(delegate);
- DelegateProducer<T> asDelegateProducer = (DelegateProducer<T>) delegateProducer;
- if (asDelegateProducer.delegate != null) {
- throw new IllegalStateException();
- }
- asDelegateProducer.delegate = (CancellableProducer<T>) delegate;
- }
-
- /**
- * Returns the factory's delegate.
- *
- * @throws NullPointerException if the delegate has not been set
- */
- CancellableProducer<T> getDelegate() {
- return checkNotNull(delegate);
- }
-
- @Override
- public void cancel(boolean mayInterruptIfRunning) {
- delegate.cancel(mayInterruptIfRunning);
- }
-
- @Override
- public Producer<T> newDependencyView() {
- return new ProducerView<T>() {
- @Override
- Producer<T> createDelegate() {
- return delegate.newDependencyView();
- }
- };
- }
-
- @Override
- public Producer<T> newEntryPointView(final CancellationListener cancellationListener) {
- return new ProducerView<T>() {
- @Override
- Producer<T> createDelegate() {
- return delegate.newEntryPointView(cancellationListener);
- }
- };
- }
-
- private abstract static class ProducerView<T> implements Producer<T> {
- private final Provider<Producer<T>> delegate =
- DoubleCheck.provider(
- new Provider<Producer<T>>() {
- @Override
- public Producer<T> get() {
- return createDelegate();
- }
- });
-
- abstract Producer<T> createDelegate();
-
- @Override
- public ListenableFuture<T> get() {
- return delegate.get().get();
- }
- }
-}
diff --git a/java/dagger/producers/internal/DependencyMethodProducer.java b/java/dagger/producers/internal/DependencyMethodProducer.java
deleted file mode 100644
index be118f2..0000000
--- a/java/dagger/producers/internal/DependencyMethodProducer.java
+++ /dev/null
@@ -1,119 +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.producers.internal;
-
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.collect.MapMaker;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Abstract class for implementing producers derived from methods on component dependencies.
- *
- * <p>Unlike most other {@link CancellableProducer} implementations, cancelling the future returned
- * by a {@linkplain #newDependencyView dependency view} injected into an {@code @Produces} method
- * will actually cancel the underlying future. This is because the future comes from outside the
- * component's producer graph (including possibly from another object that isn't a component at
- * all), so if we don't cancel it when the user asks to cancel it, there might just be no way to
- * cancel it at all.
- */
-public abstract class DependencyMethodProducer<T> implements CancellableProducer<T> {
-
- /** Weak set of all incomplete futures this producer has returned. */
- private final Set<ListenableFuture<T>> futures =
- Collections.newSetFromMap(new MapMaker().weakKeys().<ListenableFuture<T>, Boolean>makeMap());
-
- private boolean cancelled = false;
-
- /** Calls a method on a component dependency to get a future. */
- protected abstract ListenableFuture<T> callDependencyMethod();
-
- @Override
- public final ListenableFuture<T> get() {
- synchronized (futures) {
- if (cancelled) {
- return Futures.immediateCancelledFuture();
- }
-
- final ListenableFuture<T> future = callDependencyMethod();
- if (!future.isDone() && futures.add(future)) {
- future.addListener(
- new Runnable() {
- @Override
- public void run() {
- synchronized (futures) {
- futures.remove(future);
- }
- }
- },
- directExecutor());
- }
- return future;
- }
- }
-
- @Override
- public final void cancel(boolean mayInterruptIfRunning) {
- synchronized (futures) {
- cancelled = true;
- for (ListenableFuture<T> future : futures) {
- // futures is a concurrent set so that the concurrent removal that will happen here is not
- // a problem
- future.cancel(mayInterruptIfRunning);
- }
- }
- }
-
- @Override
- public final Producer<T> newDependencyView() {
- return this;
- }
-
- @Override
- public final Producer<T> newEntryPointView(final CancellationListener cancellationListener) {
- return new Producer<T>() {
- private final Set<ListenableFuture<T>> entryPointFutures =
- Collections.newSetFromMap(
- new MapMaker().weakKeys().<ListenableFuture<T>, Boolean>makeMap());
-
- @Override
- public ListenableFuture<T> get() {
- final ListenableFuture<T> future = DependencyMethodProducer.this.get();
- if (!future.isDone() && entryPointFutures.add(future)) {
- future.addListener(
- new Runnable() {
- @Override
- public void run() {
- entryPointFutures.remove(future);
- if (future.isCancelled()) {
- // TODO(cgdecker): Make this also propagate the actual value that was passed for
- // mayInterruptIfRunning
- cancellationListener.onProducerFutureCancelled(true);
- }
- }
- },
- directExecutor());
- }
- return future;
- }
- };
- }
-}
diff --git a/java/dagger/producers/internal/MapOfProducedProducer.java b/java/dagger/producers/internal/MapOfProducedProducer.java
deleted file mode 100644
index bd9f1bf..0000000
--- a/java/dagger/producers/internal/MapOfProducedProducer.java
+++ /dev/null
@@ -1,122 +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.producers.internal;
-
-import static com.google.common.util.concurrent.Futures.transform;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.List;
-import java.util.Map;
-import javax.inject.Provider;
-
-/**
- * A {@link Producer} implementation used to implement {@link Map} bindings. This producer returns a
- * {@code Map<K, Produced<V>>} which is populated by calls to the delegate {@link Producer#get}
- * methods.
- */
-public final class MapOfProducedProducer<K, V> extends AbstractMapProducer<K, V, Produced<V>> {
- private MapOfProducedProducer(ImmutableMap<K, Producer<V>> contributingMap) {
- super(contributingMap);
- }
-
- @Override
- public ListenableFuture<Map<K, Produced<V>>> compute() {
- return Futures.transform(
- Futures.allAsList(
- Iterables.transform(
- contributingMap().entrySet(), MapOfProducedProducer.<K, V>entryUnwrapper())),
- new Function<List<Map.Entry<K, Produced<V>>>, Map<K, Produced<V>>>() {
- @Override
- public Map<K, Produced<V>> apply(List<Map.Entry<K, Produced<V>>> entries) {
- return ImmutableMap.copyOf(entries);
- }
- },
- directExecutor());
- }
-
- private static final Function<
- Map.Entry<Object, Producer<Object>>,
- ListenableFuture<Map.Entry<Object, Produced<Object>>>>
- ENTRY_UNWRAPPER =
- new Function<
- Map.Entry<Object, Producer<Object>>,
- ListenableFuture<Map.Entry<Object, Produced<Object>>>>() {
- @Override
- public ListenableFuture<Map.Entry<Object, Produced<Object>>> apply(
- final Map.Entry<Object, Producer<Object>> entry) {
- return transform(
- Producers.createFutureProduced(entry.getValue().get()),
- new Function<Produced<Object>, Map.Entry<Object, Produced<Object>>>() {
- @Override
- public Map.Entry<Object, Produced<Object>> apply(Produced<Object> value) {
- return Maps.immutableEntry(entry.getKey(), value);
- }
- },
- directExecutor());
- }
- };
-
- @SuppressWarnings({"unchecked", "rawtypes"}) // bivariate implementation
- private static <K, V>
- Function<Map.Entry<K, Producer<V>>, ListenableFuture<Map.Entry<K, Produced<V>>>>
- entryUnwrapper() {
- return (Function) ENTRY_UNWRAPPER;
- }
-
- /** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- /** A builder for {@link MapOfProducedProducer}. */
- public static final class Builder<K, V> extends AbstractMapProducer.Builder<K, V, Produced<V>> {
- private Builder(int size) {
- super(size);
- }
-
- @Override
- public Builder<K, V> put(K key, Producer<V> producerOfValue) {
- super.put(key, producerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- super.put(key, providerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> putAll(Producer<Map<K, Produced<V>>> mapOfProducedProducer) {
- super.putAll(mapOfProducedProducer);
- return this;
- }
-
- /** Returns a new {@link MapOfProducedProducer}. */
- public MapOfProducedProducer<K, V> build() {
- return new MapOfProducedProducer<>(mapBuilder.build());
- }
- }
-}
diff --git a/java/dagger/producers/internal/MapOfProducerProducer.java b/java/dagger/producers/internal/MapOfProducerProducer.java
deleted file mode 100644
index 064cf74..0000000
--- a/java/dagger/producers/internal/MapOfProducerProducer.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.producers.internal;
-
-import static dagger.producers.internal.Producers.entryPointViewOf;
-import static dagger.producers.internal.Producers.nonCancellationPropagatingViewOf;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import java.util.Map;
-import javax.inject.Provider;
-
-/**
- * A {@link Producer} implementation used to implement {@link Map} bindings. This factory returns an
- * immediate future of {@code Map<K, Producer<V>>} when calling {@link #get}.
- */
-public final class MapOfProducerProducer<K, V> extends AbstractMapProducer<K, V, Producer<V>> {
- /** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- private MapOfProducerProducer(ImmutableMap<K, Producer<V>> contributingMap) {
- super(contributingMap);
- }
-
- @Override
- public ListenableFuture<Map<K, Producer<V>>> compute() {
- return Futures.<Map<K, Producer<V>>>immediateFuture(contributingMap());
- }
-
- /** A builder for {@link MapOfProducerProducer} */
- public static final class Builder<K, V> extends AbstractMapProducer.Builder<K, V, Producer<V>> {
- private Builder(int size) {
- super(size);
- }
-
- @Override
- public Builder<K, V> put(K key, Producer<V> producerOfValue) {
- super.put(key, producerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- super.put(key, providerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> putAll(Producer<Map<K, Producer<V>>> mapOfProducerProducer) {
- super.putAll(mapOfProducerProducer);
- return this;
- }
-
- /** Returns a new {@link MapOfProducerProducer}. */
- public MapOfProducerProducer<K, V> build() {
- return new MapOfProducerProducer<>(mapBuilder.build());
- }
- }
-
- @Override
- public Producer<Map<K, Producer<V>>> newDependencyView() {
- return newTransformedValuesView(MapOfProducerProducer.<V>toDependencyView());
- }
-
- @Override
- public Producer<Map<K, Producer<V>>> newEntryPointView(
- CancellationListener cancellationListener) {
- return newTransformedValuesView(
- MapOfProducerProducer.<V>toEntryPointView(cancellationListener));
- }
-
- private Producer<Map<K, Producer<V>>> newTransformedValuesView(
- Function<Producer<V>, Producer<V>> valueTransformationFunction) {
- return dagger.producers.Producers.<Map<K, Producer<V>>>immediateProducer(
- ImmutableMap.copyOf(Maps.transformValues(contributingMap(), valueTransformationFunction)));
- }
-
- @SuppressWarnings("unchecked")
- private static <T> Function<Producer<T>, Producer<T>> toDependencyView() {
- return (Function) TO_DEPENDENCY_VIEW;
- }
-
- private static <T> Function<Producer<T>, Producer<T>> toEntryPointView(
- final CancellationListener cancellationListener) {
- return new Function<Producer<T>, Producer<T>>() {
- @Override
- public Producer<T> apply(Producer<T> input) {
- return entryPointViewOf(input, cancellationListener);
- }
- };
- }
-
- private static final Function<Producer<?>, Producer<?>> TO_DEPENDENCY_VIEW =
- new Function<Producer<?>, Producer<?>>() {
- @Override
- public Producer<?> apply(Producer<?> input) {
- return nonCancellationPropagatingViewOf(input);
- }
- };
-}
diff --git a/java/dagger/producers/internal/MapProducer.java b/java/dagger/producers/internal/MapProducer.java
deleted file mode 100644
index 8caeb45..0000000
--- a/java/dagger/producers/internal/MapProducer.java
+++ /dev/null
@@ -1,103 +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.producers.internal;
-
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import javax.inject.Provider;
-
-/**
- * A {@link Producer} implementation used to implement {@link Map} bindings. This producer returns a
- * {@code Map<K, V>} which is populated by calls to the delegate {@link Producer#get} methods.
- */
-public final class MapProducer<K, V> extends AbstractMapProducer<K, V, V> {
- private MapProducer(ImmutableMap<K, Producer<V>> contributingMap) {
- super(contributingMap);
- }
-
- /** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- /** A builder for {@link MapProducer} */
- public static final class Builder<K, V> extends AbstractMapProducer.Builder<K, V, V> {
- private Builder(int size) {
- super(size);
- }
-
- @Override
- public Builder<K, V> put(K key, Producer<V> producerOfValue) {
- super.put(key, producerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- super.put(key, providerOfValue);
- return this;
- }
-
- @Override
- public Builder<K, V> putAll(Producer<Map<K, V>> mapProducer) {
- super.putAll(mapProducer);
- return this;
- }
-
- /** Returns a new {@link MapProducer}. */
- public MapProducer<K, V> build() {
- return new MapProducer<>(mapBuilder.build());
- }
- }
-
- @Override
- protected ListenableFuture<Map<K, V>> compute() {
- final List<ListenableFuture<Map.Entry<K, V>>> listOfEntries = new ArrayList<>();
- for (final Entry<K, Producer<V>> entry : contributingMap().entrySet()) {
- listOfEntries.add(
- Futures.transform(
- entry.getValue().get(),
- new Function<V, Entry<K, V>>() {
- @Override
- public Entry<K, V> apply(V computedValue) {
- return Maps.immutableEntry(entry.getKey(), computedValue);
- }
- },
- directExecutor()));
- }
-
- return Futures.transform(
- Futures.allAsList(listOfEntries),
- new Function<List<Map.Entry<K, V>>, Map<K, V>>() {
- @Override
- public Map<K, V> apply(List<Map.Entry<K, V>> entries) {
- return ImmutableMap.copyOf(entries);
- }
- },
- directExecutor());
- }
-}
diff --git a/java/dagger/producers/internal/MissingBindingProducer.java b/java/dagger/producers/internal/MissingBindingProducer.java
deleted file mode 100644
index 5721569..0000000
--- a/java/dagger/producers/internal/MissingBindingProducer.java
+++ /dev/null
@@ -1,46 +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.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/internal/Producers.java b/java/dagger/producers/internal/Producers.java
deleted file mode 100644
index 54e4d5e..0000000
--- a/java/dagger/producers/internal/Producers.java
+++ /dev/null
@@ -1,237 +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.producers.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.util.concurrent.Futures.catchingAsync;
-import static com.google.common.util.concurrent.Futures.transform;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Provider;
-
-/**
- * Utility methods for use in generated producer code.
- */
-public final class Producers {
- /**
- * Returns a future of {@link Produced} that represents the completion (either success or failure)
- * of the given future. If the input future succeeds, then the resulting future also succeeds with
- * a successful {@code Produced}; if the input future fails, then the resulting future succeeds
- * with a failing {@code Produced}.
- *
- * <p>Cancelling the resulting future will propagate the cancellation to the input future; but
- * cancelling the input future will trigger the resulting future to succeed with a failing
- * {@code Produced}.
- */
- // TODO(beder): Document what happens with an InterruptedException after you figure out how to
- // trigger one in a test.
- public static <T> ListenableFuture<Produced<T>> createFutureProduced(ListenableFuture<T> future) {
- return catchingAsync(
- transform(future, Producers.<T>resultToProduced(), directExecutor()),
- Throwable.class,
- Producers.<T>futureFallbackForProduced(),
- directExecutor());
- }
-
- private static final Function<Object, Produced<Object>> RESULT_TO_PRODUCED =
- new Function<Object, Produced<Object>>() {
- @Override
- public Produced<Object> apply(Object result) {
- return Produced.successful(result);
- }
- };
-
- @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
- private static <T> Function<T, Produced<T>> resultToProduced() {
- return (Function) RESULT_TO_PRODUCED;
- }
-
- private static final AsyncFunction<Throwable, Produced<Object>> FUTURE_FALLBACK_FOR_PRODUCED =
- new AsyncFunction<Throwable, Produced<Object>>() {
- @Override
- public ListenableFuture<Produced<Object>> apply(Throwable t) throws Exception {
- Produced<Object> produced = Produced.failed(t);
- return Futures.immediateFuture(produced);
- }
- };
-
- @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
- private static <T> AsyncFunction<Throwable, Produced<T>> futureFallbackForProduced() {
- return (AsyncFunction) FUTURE_FALLBACK_FOR_PRODUCED;
- }
-
- /**
- * Returns a future of a {@code Set} that contains a single element: the result of the input
- * future.
- */
- public static <T> ListenableFuture<Set<T>> createFutureSingletonSet(ListenableFuture<T> future) {
- return transform(
- future,
- new Function<T, Set<T>>() {
- @Override
- public Set<T> apply(T value) {
- return ImmutableSet.of(value);
- }
- },
- directExecutor());
- }
-
- /**
- * Creates a new {@code ListenableFuture} whose value is a set containing the values of all its
- * input futures, if all succeed. If any input fails, the returned future fails immediately.
- *
- * <p>This is the set equivalent of {@link Futures#allAsList}.
- */
- public static <T> ListenableFuture<Set<T>> allAsSet(
- Iterable<? extends ListenableFuture<? extends T>> futures) {
- return transform(
- Futures.allAsList(futures),
- new Function<List<T>, Set<T>>() {
- @Override
- public Set<T> apply(List<T> values) {
- return ImmutableSet.copyOf(values);
- }
- },
- directExecutor());
- }
-
- /**
- * Returns a producer that immediately executes the binding logic for the given provider every
- * time it is called.
- */
- public static <T> Producer<T> producerFromProvider(final Provider<T> provider) {
- checkNotNull(provider);
- return new CompletedProducer<T>() {
- @Override
- public ListenableFuture<T> get() {
- return Futures.immediateFuture(provider.get());
- }
- };
- }
-
- /**
- * Returns a producer that succeeds with the given value.
- *
- * @deprecated Prefer the non-internal version of this method: {@link
- * dagger.producers.Producers#immediateProducer(Object)}.
- */
- @Deprecated
- public static <T> Producer<T> immediateProducer(T value) {
- return dagger.producers.Producers.immediateProducer(value);
- }
-
- /**
- * Returns a producer that fails with the given exception.
- *
- * @deprecated Prefer the non-internal version of this method: {@link
- * dagger.producers.Producers#immediateFailedProducer(Throwable)}.
- */
- @Deprecated
- public static <T> Producer<T> immediateFailedProducer(Throwable throwable) {
- return dagger.producers.Producers.immediateFailedProducer(throwable);
- }
-
- /**
- * Returns a new view of the given {@code producer} if and only if it is a {@link
- * CancellableProducer}. Cancelling the returned producer's future will not cancel the underlying
- * task for the given producer.
- *
- * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
- */
- public static <T> Producer<T> nonCancellationPropagatingViewOf(Producer<T> producer) {
- // This is a hack until we change the types of Producer fields to be CancellableProducer or
- // some other type.
- if (producer instanceof CancellableProducer) {
- return ((CancellableProducer<T>) producer).newDependencyView();
- }
- throw new IllegalArgumentException(
- "nonCancellationPropagatingViewOf called with non-CancellableProducer: " + producer);
- }
-
- /**
- * Returns a new view of the given {@code producer} for use as an entry point in a production
- * component, if and only if it is a {@link CancellableProducer}. When the returned producer's
- * future is cancelled, the given {@code cancellable} will also be cancelled.
- *
- * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
- */
- public static <T> Producer<T> entryPointViewOf(
- Producer<T> producer, CancellationListener cancellationListener) {
- // This is a hack until we change the types of Producer fields to be CancellableProducer or
- // some other type.
- if (producer instanceof CancellableProducer) {
- return ((CancellableProducer<T>) producer).newEntryPointView(cancellationListener);
- }
- throw new IllegalArgumentException(
- "entryPointViewOf called with non-CancellableProducer: " + producer);
- }
-
- /**
- * Calls {@code cancel} on the given {@code producer} if it is a {@link CancellableProducer}.
- *
- * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
- */
- public static void cancel(Producer<?> producer, boolean mayInterruptIfRunning) {
- // This is a hack until we change the types of Producer fields to be CancellableProducer or
- // some other type.
- if (producer instanceof CancellableProducer) {
- ((CancellableProducer<?>) producer).cancel(mayInterruptIfRunning);
- } else {
- throw new IllegalArgumentException("cancel called with non-CancellableProducer: " + producer);
- }
- }
-
- private static final Producer<Map<Object, Object>> EMPTY_MAP_PRODUCER =
- dagger.producers.Producers.<Map<Object, Object>>immediateProducer(ImmutableMap.of());
-
- @SuppressWarnings("unchecked") // safe contravariant cast
- public static <K, V> Producer<Map<K, V>> emptyMapProducer() {
- return (Producer<Map<K, V>>) (Producer) EMPTY_MAP_PRODUCER;
- }
-
- /**
- * A {@link CancellableProducer} which can't be cancelled because it represents an
- * already-completed task.
- */
- private abstract static class CompletedProducer<T> implements CancellableProducer<T> {
- @Override
- public void cancel(boolean mayInterruptIfRunning) {}
-
- @Override
- public Producer<T> newDependencyView() {
- return this;
- }
-
- @Override
- public Producer<T> newEntryPointView(CancellationListener cancellationListener) {
- return this;
- }
- }
-
- private Producers() {}
-}
diff --git a/java/dagger/producers/internal/ProductionExecutorModule.java b/java/dagger/producers/internal/ProductionExecutorModule.java
deleted file mode 100644
index e233ae9..0000000
--- a/java/dagger/producers/internal/ProductionExecutorModule.java
+++ /dev/null
@@ -1,37 +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.producers.internal;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.producers.Production;
-import dagger.producers.ProductionScope;
-import java.util.concurrent.Executor;
-
-/**
- * Binds the {@code @ProductionImplementation Executor} binding in {@link ProductionScope} so that
- * only on instance is ever used within production components.
- */
-@Module
-public abstract class ProductionExecutorModule {
- @Binds
- @ProductionScope
- @ProductionImplementation
- abstract Executor productionImplementationExecutor(@Production Executor executor);
-
- private ProductionExecutorModule() {}
-}
diff --git a/java/dagger/producers/internal/ProductionImplementation.java b/java/dagger/producers/internal/ProductionImplementation.java
deleted file mode 100644
index 8a0149c..0000000
--- a/java/dagger/producers/internal/ProductionImplementation.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.producers.internal;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.Beta;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * Qualifies a type that will be used as an internal implementation detail in the framework.
- *
- * <p>This is only intended to be used by the framework. It is the internal counterpart to
- * {@link dagger.producers.Production}.
- */
-@Documented
-@Retention(RUNTIME)
-@Qualifier
-@Beta
-public @interface ProductionImplementation {}
diff --git a/java/dagger/producers/internal/SetOfProducedProducer.java b/java/dagger/producers/internal/SetOfProducedProducer.java
deleted file mode 100644
index 40833e5..0000000
--- a/java/dagger/producers/internal/SetOfProducedProducer.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.producers.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static dagger.internal.DaggerCollections.hasDuplicates;
-import static dagger.internal.DaggerCollections.presizedList;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-
-/**
- * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns a
- * future {@code Set<Produced<T>>} whose elements are populated by subsequent calls to the delegate
- * {@link Producer#get} methods.
- */
-public final class SetOfProducedProducer<T> extends AbstractProducer<Set<Produced<T>>> {
- public static <T> Producer<Set<T>> empty() {
- return SetProducer.empty();
- }
-
- /**
- * Constructs a new {@link Builder} for a {@link SetProducer} with {@code individualProducerSize}
- * individual {@code Producer<T>} and {@code collectionProducerSize} {@code
- * Producer<Collection<T>>} instances.
- */
- public static <T> Builder<T> builder(int individualProducerSize, int collectionProducerSize) {
- return new Builder<T>(individualProducerSize, collectionProducerSize);
- }
-
- /**
- * A builder to accumulate {@code Producer<T>} and {@code Producer<Collection<T>>} instances.
- * These are only intended to be single-use and from within generated code. Do <em>NOT</em> add
- * producers after calling {@link #build()}.
- */
- public static final class Builder<T> {
- private final List<Producer<T>> individualProducers;
- private final List<Producer<Collection<T>>> collectionProducers;
-
- private Builder(int individualProducerSize, int collectionProducerSize) {
- individualProducers = presizedList(individualProducerSize);
- collectionProducers = presizedList(collectionProducerSize);
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addProducer(Producer<? extends T> individualProducer) {
- assert individualProducer != null : "Codegen error? Null producer";
- individualProducers.add((Producer<T>) individualProducer);
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addCollectionProducer(
- Producer<? extends Collection<? extends T>> multipleProducer) {
- assert multipleProducer != null : "Codegen error? Null producer";
- collectionProducers.add((Producer<Collection<T>>) multipleProducer);
- return this;
- }
-
- public SetOfProducedProducer<T> build() {
- assert !hasDuplicates(individualProducers)
- : "Codegen error? Duplicates in the producer list";
- assert !hasDuplicates(collectionProducers)
- : "Codegen error? Duplicates in the producer list";
-
- return new SetOfProducedProducer<T>(individualProducers, collectionProducers);
- }
- }
-
- private final List<Producer<T>> individualProducers;
- private final List<Producer<Collection<T>>> collectionProducers;
-
- private SetOfProducedProducer(
- List<Producer<T>> individualProducers, List<Producer<Collection<T>>> collectionProducers) {
- this.individualProducers = individualProducers;
- this.collectionProducers = collectionProducers;
- }
-
- /**
- * Returns a future {@link Set} of {@link Produced} elements given by each of the producers.
- *
- * <p>If any of the delegate collections, or any elements therein, are null, then that
- * corresponding {@code Produced} element will fail with a NullPointerException.
- *
- * <p>Canceling this future will attempt to cancel all of the component futures; but if any of the
- * delegate futures fail or are canceled, this future succeeds, with the appropriate failed {@link
- * Produced}.
- *
- * @throws NullPointerException if any of the delegate producers return null
- */
- @Override
- public ListenableFuture<Set<Produced<T>>> compute() {
- List<ListenableFuture<? extends Produced<? extends Collection<T>>>> futureProducedCollections =
- new ArrayList<ListenableFuture<? extends Produced<? extends Collection<T>>>>(
- individualProducers.size() + collectionProducers.size());
- for (Producer<T> producer : individualProducers) {
- // TODO(ronshapiro): Don't require individual productions to be added to a collection just to
- // be materialized into futureProducedCollections.
- futureProducedCollections.add(
- Producers.createFutureProduced(
- Producers.createFutureSingletonSet(checkNotNull(producer.get()))));
- }
- for (Producer<Collection<T>> producer : collectionProducers) {
- futureProducedCollections.add(Producers.createFutureProduced(checkNotNull(producer.get())));
- }
-
- return Futures.transform(
- Futures.allAsList(futureProducedCollections),
- new Function<List<Produced<? extends Collection<T>>>, Set<Produced<T>>>() {
- @Override
- public Set<Produced<T>> apply(
- List<Produced<? extends Collection<T>>> producedCollections) {
- ImmutableSet.Builder<Produced<T>> builder = ImmutableSet.builder();
- for (Produced<? extends Collection<T>> producedCollection : producedCollections) {
- try {
- Collection<T> collection = producedCollection.get();
- if (collection == null) {
- // TODO(beder): This is a vague exception. Can we somehow point to the failing
- // producer? See the similar comment in the component writer about null
- // provisions.
- builder.add(
- Produced.<T>failed(
- new NullPointerException(
- "Cannot contribute a null collection into a producer set binding when"
- + " it's injected as Set<Produced<T>>.")));
- } else {
- for (T value : collection) {
- if (value == null) {
- builder.add(
- Produced.<T>failed(
- new NullPointerException(
- "Cannot contribute a null element into a producer set binding"
- + " when it's injected as Set<Produced<T>>.")));
- } else {
- builder.add(Produced.successful(value));
- }
- }
- }
- } catch (ExecutionException e) {
- builder.add(Produced.<T>failed(e.getCause()));
- }
- }
- return builder.build();
- }
- },
- directExecutor());
- }
-}
diff --git a/java/dagger/producers/internal/SetProducer.java b/java/dagger/producers/internal/SetProducer.java
deleted file mode 100644
index c0196ae..0000000
--- a/java/dagger/producers/internal/SetProducer.java
+++ /dev/null
@@ -1,147 +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.producers.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.util.concurrent.Futures.transform;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static dagger.internal.DaggerCollections.hasDuplicates;
-import static dagger.internal.DaggerCollections.presizedList;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns
- * a future {@link Set} whose elements are populated by subsequent calls to the delegate
- * {@link Producer#get} methods.
- */
-public final class SetProducer<T> extends AbstractProducer<Set<T>> {
- private static final Producer<Set<Object>> EMPTY_PRODUCER =
- dagger.producers.Producers.<Set<Object>>immediateProducer(ImmutableSet.<Object>of());
-
- @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
- public static <T> Producer<Set<T>> empty() {
- return (Producer) EMPTY_PRODUCER;
- }
-
- /**
- * Constructs a new {@link Builder} for a {@link SetProducer} with {@code individualProducerSize}
- * individual {@code Producer<T>} and {@code collectionProducerSize} {@code
- * Producer<Collection<T>>} instances.
- */
- public static <T> Builder<T> builder(int individualProducerSize, int collectionProducerSize) {
- return new Builder<T>(individualProducerSize, collectionProducerSize);
- }
-
- /**
- * A builder to accumulate {@code Producer<T>} and {@code Producer<Collection<T>>} instances.
- * These are only intended to be single-use and from within generated code. Do <em>NOT</em> add
- * producers after calling {@link #build()}.
- */
- public static final class Builder<T> {
- private final List<Producer<T>> individualProducers;
- private final List<Producer<Collection<T>>> collectionProducers;
-
- private Builder(int individualProducerSize, int collectionProducerSize) {
- individualProducers = presizedList(individualProducerSize);
- collectionProducers = presizedList(collectionProducerSize);
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addProducer(Producer<? extends T> individualProducer) {
- assert individualProducer != null : "Codegen error? Null producer";
- individualProducers.add((Producer<T>) individualProducer);
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public Builder<T> addCollectionProducer(
- Producer<? extends Collection<? extends T>> multipleProducer) {
- assert multipleProducer != null : "Codegen error? Null producer";
- collectionProducers.add((Producer<Collection<T>>) multipleProducer);
- return this;
- }
-
- public SetProducer<T> build() {
- assert !hasDuplicates(individualProducers)
- : "Codegen error? Duplicates in the producer list";
- assert !hasDuplicates(collectionProducers)
- : "Codegen error? Duplicates in the producer list";
-
- return new SetProducer<T>(individualProducers, collectionProducers);
- }
- }
-
- private final List<Producer<T>> individualProducers;
- private final List<Producer<Collection<T>>> collectionProducers;
-
- private SetProducer(
- List<Producer<T>> individualProducers, List<Producer<Collection<T>>> collectionProducers) {
- this.individualProducers = individualProducers;
- this.collectionProducers = collectionProducers;
- }
-
- /**
- * Returns a future {@link Set} that contains the elements given by each of the producers.
- *
- * <p>If any of the delegate collections, or any elements therein, are null, then this future will
- * fail with a NullPointerException.
- *
- * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the
- * delegate futures fails or is canceled, this one is, too.
- *
- * @throws NullPointerException if any of the delegate producers return null
- */
- @Override
- public ListenableFuture<Set<T>> compute() {
- List<ListenableFuture<T>> individualFutures =
- new ArrayList<ListenableFuture<T>>(individualProducers.size());
- for (Producer<T> producer : individualProducers) {
- individualFutures.add(checkNotNull(producer.get()));
- }
-
- // Presize the list of collections produced by the amount of collectionProducers, with one more
- // for the consolidate individualFutures from Futures.allAsList.
- List<ListenableFuture<? extends Collection<T>>> futureCollections =
- new ArrayList<ListenableFuture<? extends Collection<T>>>(collectionProducers.size() + 1);
- futureCollections.add(Futures.allAsList(individualFutures));
- for (Producer<Collection<T>> producer : collectionProducers) {
- futureCollections.add(checkNotNull(producer.get()));
- }
- return transform(
- Futures.allAsList(futureCollections),
- new Function<List<Collection<T>>, Set<T>>() {
- @Override
- public Set<T> apply(List<Collection<T>> sets) {
- ImmutableSet.Builder<T> builder = ImmutableSet.builder();
- for (Collection<T> set : sets) {
- builder.addAll(set);
- }
- return builder.build();
- }
- },
- directExecutor());
- }
-}
diff --git a/java/dagger/producers/monitoring/ProducerMonitor.java b/java/dagger/producers/monitoring/ProducerMonitor.java
deleted file mode 100644
index c0379fd..0000000
--- a/java/dagger/producers/monitoring/ProducerMonitor.java
+++ /dev/null
@@ -1,193 +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.producers.monitoring;
-
-import static com.google.common.util.concurrent.Futures.addCallback;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import dagger.producers.Produces;
-
-/**
- * A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
- * {@link ProductionComponentMonitor} for how to install these monitors.
- *
- * <p>The lifecycle of the monitor, under normal conditions, is:
- * <ul>
- * <li>{@link #requested()}
- * <li>{@link #methodStarting()}
- * <li>The method is called
- * <li>{@link #methodFinished()}
- * <li>If the method returns a value, then:
- * <ul>
- * <li>{@link #succeeded(Object)} if the method returned normally; or
- * <li>{@link #failed(Throwable)} if the method threw an exception.
- * </ul>
- * <li>If the method returns a future, then:
- * <ul>
- * <li>{@link #succeeded(Object)} if the method returned normally, and the future succeeded; or
- * <li>{@link #failed(Throwable)} if the method threw an exception, or returned normally and the
- * future failed.
- * </ul>
- * </ul>
- *
- * <p>If any input to the monitored producer fails, {@link #failed(Throwable)} will be called
- * immediately with the failed input's exception. If more than one input fails, an arbitrary failed
- * input's exception is used.
- *
- * <p>For example, given an entry point A that depends on B, which depends on C, when the entry
- * point A is called, this will trigger the following sequence of events, assuming all methods and
- * futures complete successfully:
- * <ul>
- * <li>A requested
- * <li>B requested
- * <li>C requested
- * <li>C methodStarting
- * <li>C methodFinished
- * <li>C succeeded
- * <li>B methodStarting
- * <li>B methodFinished
- * <li>B succeeded
- * <li>A methodStarting
- * <li>A methodFinished
- * <li>A succeeded
- * </ul>
- *
- * <p>If any of the monitor's methods throw, then the exception will be logged and processing will
- * continue unaffected.
- *
- * @since 2.1
- */
-public abstract class ProducerMonitor {
- /**
- * Called when the producer's output is requested; that is, when the first method is called that
- * requires the production of this producer's output.
- *
- * <p>Note that if a method depends on {@code Producer<T>}, then this does not count as requesting
- * {@code T}; that is only triggered by calling {@link Producer#get()}.
- *
- * <p>Depending on how this producer is requested, the following threading constraints are
- * guaranteed:
- *
- * <ol>
- * <li>If the producer is requested directly by a method on a component, then {@code requested}
- * will be called on the same thread as the component method call.
- * <li>If the producer is requested by value from another producer (i.e., injected as {@code T}
- * or {@code Produced<T>}), then {@code requested} will be called from the same thread as
- * the other producer's {@code requested}.
- * <li>If the producer is requested by calling {@link Producer#get()}, then {@code requested}
- * will be called from the same thread as that {@code get()} call.
- * </ol>
- *
- * <p>When multiple monitors are installed, the order that each monitor will call this method is
- * unspecified, but will remain consistent throughout the course of the execution of a component.
- *
- * <p>This implementation is a no-op.
- */
- public void requested() {}
-
- /**
- * Called when all of the producer's inputs are available. This is called regardless of whether
- * the inputs have succeeded or not; when the inputs have succeeded, this is called prior to
- * scheduling the method on the executor, and if an input has failed and the producer will be
- * skipped, this method will be called before {@link #failed(Throwable)} is called.
- *
- * <p>When multiple monitors are installed, the order that each monitor will call this method is
- * unspecified, but will remain consistent throughout the course of the execution of a component.
- *
- * <p>This implementation is a no-op.
- */
- public void ready() {}
-
- /**
- * Called when the producer method is about to start executing. This will be called from the same
- * thread as the producer method itself.
- *
- * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
- * calls to {@link #requested()}.
- *
- * <p>This implementation is a no-op.
- */
- public void methodStarting() {}
-
- /**
- * Called when the producer method has finished executing. This will be called from the same
- * thread as {@link #methodStarting()} and the producer method itself.
- *
- * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
- * calls to {@link #requested()}.
- *
- * <p>This implementation is a no-op.
- */
- public void methodFinished() {}
-
- /**
- * Called when the producer’s future has completed successfully with a value.
- *
- * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
- * calls to {@link #requested()}.
- *
- * <p>This implementation is a no-op.
- */
- public void succeeded(@SuppressWarnings("unused") Object value) {}
-
- /**
- * Called when the producer's future has failed with an exception.
- *
- * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
- * calls to {@link #requested()}.
- *
- * <p>This implementation is a no-op.
- */
- public void failed(@SuppressWarnings("unused") Throwable t) {}
-
- /**
- * Adds this monitor's completion methods as a callback to the future. This is only intended to be
- * overridden in the framework!
- */
- public <T> void addCallbackTo(ListenableFuture<T> future) {
- addCallback(
- future,
- new FutureCallback<T>() {
- @Override
- public void onSuccess(T value) {
- succeeded(value);
- }
-
- @Override
- public void onFailure(Throwable t) {
- failed(t);
- }
- },
- directExecutor());
- }
-
- private static final ProducerMonitor NO_OP =
- new ProducerMonitor() {
- @Override
- public <T> void addCallbackTo(ListenableFuture<T> future) {
- // overridden to avoid adding a do-nothing callback
- }
- };
-
- /** Returns a monitor that does no monitoring. */
- public static ProducerMonitor noOp() {
- return NO_OP;
- }
-}
diff --git a/java/dagger/producers/monitoring/ProducerTimingRecorder.java b/java/dagger/producers/monitoring/ProducerTimingRecorder.java
deleted file mode 100644
index f4894c9..0000000
--- a/java/dagger/producers/monitoring/ProducerTimingRecorder.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.producers.monitoring;
-
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-
-/**
- * A hook for recording the timing of the execution of individual
- * {@linkplain Produces producer methods}. See {@link ProductionComponentTimingRecorder} for how to
- * install these monitors.
- *
- * <p>If any of the recorder's methods throw, then the exception will be logged and processing will
- * continue unaffected.
- *
- * <p>All timings are measured at nanosecond precision, but not necessarily nanosecond resolution.
- * That is, timings will be reported in nanoseconds, but the timing source will not necessarily
- * update at nanosecond resolution. For example, {@link System#nanoTime()} would satisfy these
- * constraints.
- *
- * @since 2.1
- */
-public abstract class ProducerTimingRecorder {
- /**
- * Reports that the producer method has finished executing with the given statistics.
- *
- * <p>If the producer was skipped due to any of its inputs failing, then this will not be called.
- *
- * @param startedNanos the wall-clock time, in nanoseconds, when the producer method started
- * executing, measured from when the first method on the {@linkplain ProductionComponent
- * production component} was called.
- * @param durationNanos the wall-clock time, in nanoseconds, that the producer method took to
- * execute.
- */
- @SuppressWarnings("GoodTime") // should accept a java.time.Duration x2 (?)
- public void recordMethod(long startedNanos, long durationNanos) {}
-
- /**
- * Reports that the producer's future has succeeded with the given statistics.
- *
- * <p>If the producer was skipped due to any of its inputs failing, then this will not be called.
- *
- * @param latencyNanos the wall-clock time, in nanoseconds, of the producer's latency, measured
- * from when the producer method started to when the future finished.
- */
- @SuppressWarnings("GoodTime") // should accept a java.time.Duration
- public void recordSuccess(long latencyNanos) {}
-
- /**
- * Reports that the producer's future has failed with the given statistics.
- *
- * @param exception the exception that the future failed with.
- * @param latencyNanos the wall-clock time, in nanoseconds, of the producer's latency, measured
- * from when the producer method started to when the future finished.
- */
- @SuppressWarnings("GoodTime") // should accept a java.time.Duration
- public void recordFailure(Throwable exception, long latencyNanos) {}
-
- /**
- * Reports that the producer was skipped because one of its inputs failed.
- *
- * @param exception the exception that its input failed with. If multiple inputs failed, this
- * exception will be chosen arbitrarily from the input failures.
- */
- public void recordSkip(Throwable exception) {}
-
- /** Returns a producer recorder that does nothing. */
- public static ProducerTimingRecorder noOp() {
- return NO_OP;
- }
-
- private static final ProducerTimingRecorder NO_OP = new ProducerTimingRecorder() {};
-}
diff --git a/java/dagger/producers/monitoring/ProducerToken.java b/java/dagger/producers/monitoring/ProducerToken.java
deleted file mode 100644
index 1f05146..0000000
--- a/java/dagger/producers/monitoring/ProducerToken.java
+++ /dev/null
@@ -1,91 +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.producers.monitoring;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import dagger.producers.Produces;
-import java.util.Objects;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/** A token that represents an individual {@linkplain Produces producer method}. */
-public final class ProducerToken {
- @NullableDecl private final Class<?> classToken;
- @NullableDecl private final String methodName;
-
- private ProducerToken(@NullableDecl Class<?> classToken, @NullableDecl String methodName) {
- this.classToken = classToken;
- this.methodName = methodName;
- }
-
- /**
- * Creates a token for a class token that represents the generated factory for a producer method.
- *
- * <p><b>Do not use this!</b> This is intended to be called by generated code only, and its
- * signature may change at any time.
- */
- public static ProducerToken create(Class<?> classToken) {
- return new ProducerToken(checkNotNull(classToken), null);
- }
-
- /**
- * Creates a token for a producer method.
- *
- * <p><b>Do not use this!</b> This is intended to be called by generated code only, and its
- * signature may change at any time.
- */
- public static ProducerToken create(String methodName) {
- return new ProducerToken(null, checkNotNull(methodName));
- }
-
- /** Two tokens are equal if they represent the same method. */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (o instanceof ProducerToken) {
- ProducerToken that = (ProducerToken) o;
- return Objects.equals(this.classToken, that.classToken)
- && Objects.equals(this.methodName, that.methodName);
- } else {
- return false;
- }
- }
-
- /** Returns an appropriate hash code to match {@link #equals(Object)}. */
- @Override
- public int hashCode() {
- int h = 1;
- h *= 1000003;
- h ^= Objects.hashCode(this.classToken);
- h *= 1000003;
- h ^= Objects.hashCode(this.methodName);
- return h;
- }
-
- /** Returns a representation of the method. */
- @Override
- public String toString() {
- if (methodName != null) {
- return methodName;
- } else if (classToken != null) {
- return classToken.getCanonicalName();
- } else {
- throw new IllegalStateException();
- }
- }
-}
diff --git a/java/dagger/producers/monitoring/ProductionComponentMonitor.java b/java/dagger/producers/monitoring/ProductionComponentMonitor.java
deleted file mode 100644
index ca71ece..0000000
--- a/java/dagger/producers/monitoring/ProductionComponentMonitor.java
+++ /dev/null
@@ -1,83 +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.producers.monitoring;
-
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-
-/**
- * A hook for monitoring execution of {@linkplain ProductionComponent production components}. To
- * install a {@code ProductionComponentMonitor}, contribute to a set binding of
- * {@code ProductionComponentMonitor.Factory}. The factory will be asked to create one monitor for
- * the component, and the resulting single instance will be used to create individual monitors for
- * producers.
- *
- * <p>For example: <pre><code>
- * {@literal @Module}
- * final class MyMonitorModule {
- * {@literal @Provides @IntoSet} ProductionComponentMonitor.Factory provideMonitorFactory(
- * MyProductionComponentMonitor.Factory monitorFactory) {
- * return monitorFactory;
- * }
- * }
- *
- * {@literal @ProductionComponent(modules = {MyMonitorModule.class, MyProducerModule.class})}
- * interface MyComponent {
- * {@literal ListenableFuture<SomeType>} someType();
- * }
- * </code></pre>
- *
- * <p>If any of these methods throw, then the exception will be logged, and the framework will act
- * as though a no-op monitor was returned.
- *
- * @since 2.1
- */
-public abstract class ProductionComponentMonitor {
- /** Returns a monitor for an individual {@linkplain Produces producer method}. */
- public abstract ProducerMonitor producerMonitorFor(ProducerToken token);
-
- private static final ProductionComponentMonitor NO_OP =
- new ProductionComponentMonitor() {
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- return ProducerMonitor.noOp();
- }
- };
-
- /** Returns a monitor that does no monitoring. */
- public static ProductionComponentMonitor noOp() {
- return NO_OP;
- }
-
- public abstract static class Factory {
- /** Creates a component-specific monitor when the component is created. */
- public abstract ProductionComponentMonitor create(Object component);
-
- private static final Factory NO_OP_FACTORY =
- new Factory() {
- @Override
- public ProductionComponentMonitor create(Object component) {
- return ProductionComponentMonitor.noOp();
- }
- };
-
- /** Returns a factory that returns no-op monitors. */
- public static Factory noOp() {
- return NO_OP_FACTORY;
- }
- }
-}
diff --git a/java/dagger/producers/monitoring/ProductionComponentTimingRecorder.java b/java/dagger/producers/monitoring/ProductionComponentTimingRecorder.java
deleted file mode 100644
index d82d8e1..0000000
--- a/java/dagger/producers/monitoring/ProductionComponentTimingRecorder.java
+++ /dev/null
@@ -1,43 +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.producers.monitoring;
-
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-
-/**
- * A hook for recording timing of the execution of
- * {@linkplain ProductionComponent production components}. To install a
- * {@code ProductionComponentTimingRecorder}, contribute to a set binding of
- * {@code ProductionComponentTimingRecorder.Factory}, and include the {@code TimingMonitorModule} to
- * the component. The factory will be asked to create one timing recorder for the component, and the
- * resulting instance will be used to create individual timing recorders for producers.
- *
- * <p>If any of these methods throw, then the exception will be logged, and the framework will act
- * as though a no-op timing recorder was returned.
- *
- * @since 2.1
- */
-public interface ProductionComponentTimingRecorder {
- /** Returns a timing recorder for an individual {@linkplain Produces producer method}. */
- ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token);
-
- public interface Factory {
- /** Creates a component-specific timing recorder when the component is created. */
- ProductionComponentTimingRecorder create(Object component);
- }
-}
diff --git a/java/dagger/producers/monitoring/TimingProducerMonitor.java b/java/dagger/producers/monitoring/TimingProducerMonitor.java
deleted file mode 100644
index c63e108..0000000
--- a/java/dagger/producers/monitoring/TimingProducerMonitor.java
+++ /dev/null
@@ -1,70 +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.producers.monitoring;
-
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.base.Ticker;
-
-/**
- * A monitor that measures the timing of the execution of a producer method, and logs those timings
- * with the given recorder.
- */
-final class TimingProducerMonitor extends ProducerMonitor {
- private final ProducerTimingRecorder recorder;
- private final Stopwatch stopwatch;
- private final Stopwatch componentStopwatch;
- private long startNanos = -1;
-
- TimingProducerMonitor(
- ProducerTimingRecorder recorder, Ticker ticker, Stopwatch componentStopwatch) {
- this.recorder = recorder;
- this.stopwatch = Stopwatch.createUnstarted(ticker);
- this.componentStopwatch = componentStopwatch;
- }
-
- @Override
- public void methodStarting() {
- startNanos = componentStopwatch.elapsed(NANOSECONDS);
- stopwatch.start();
- }
-
- @Override
- public void methodFinished() {
- // TODO(beder): Is a system ticker the appropriate way to track CPU time? Should we use
- // ThreadCpuTicker instead?
- long durationNanos = stopwatch.elapsed(NANOSECONDS);
- recorder.recordMethod(startNanos, durationNanos);
- }
-
- @Override
- public void succeeded(Object o) {
- long latencyNanos = stopwatch.elapsed(NANOSECONDS);
- recorder.recordSuccess(latencyNanos);
- }
-
- @Override
- public void failed(Throwable t) {
- if (stopwatch.isRunning()) {
- long latencyNanos = stopwatch.elapsed(NANOSECONDS);
- recorder.recordFailure(t, latencyNanos);
- } else {
- recorder.recordSkip(t);
- }
- }
-}
diff --git a/java/dagger/producers/monitoring/TimingProductionComponentMonitor.java b/java/dagger/producers/monitoring/TimingProductionComponentMonitor.java
deleted file mode 100644
index 66589d9..0000000
--- a/java/dagger/producers/monitoring/TimingProductionComponentMonitor.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.producers.monitoring;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.base.Ticker;
-import dagger.internal.Beta;
-
-/**
- * A monitor that measures the timing of the execution of a production component, and logs those
- * timings with the given recorder.
- *
- * <p>This assumes that the given recorders do not throw or return null; for example, by using
- * {@link TimingRecorders#delegatingProductionComponentTimingRecorderFactory}.
- */
-// TODO(beder): Reduce the visibility of this class to package-private.
-@Beta
-public final class TimingProductionComponentMonitor extends ProductionComponentMonitor {
- private final ProductionComponentTimingRecorder recorder;
- private final Ticker ticker;
- private final Stopwatch stopwatch;
-
- TimingProductionComponentMonitor(ProductionComponentTimingRecorder recorder, Ticker ticker) {
- this.recorder = recorder;
- this.ticker = ticker;
- this.stopwatch = Stopwatch.createStarted(ticker);
- }
-
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- return new TimingProducerMonitor(recorder.producerTimingRecorderFor(token), ticker, stopwatch);
- }
-
- public static final class Factory extends ProductionComponentMonitor.Factory {
- private final ProductionComponentTimingRecorder.Factory recorderFactory;
- private final Ticker ticker;
-
- public Factory(ProductionComponentTimingRecorder.Factory recorderFactory) {
- this(recorderFactory, Ticker.systemTicker());
- }
-
- Factory(ProductionComponentTimingRecorder.Factory recorderFactory, Ticker ticker) {
- this.recorderFactory = recorderFactory;
- this.ticker = ticker;
- }
-
- @Override
- public ProductionComponentMonitor create(Object component) {
- return new TimingProductionComponentMonitor(recorderFactory.create(component), ticker);
- }
- }
-}
diff --git a/java/dagger/producers/monitoring/TimingRecorders.java b/java/dagger/producers/monitoring/TimingRecorders.java
deleted file mode 100644
index 5fbe3e3..0000000
--- a/java/dagger/producers/monitoring/TimingRecorders.java
+++ /dev/null
@@ -1,347 +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.producers.monitoring;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import dagger.internal.Beta;
-import java.util.Collection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Utility methods relating to timing.
- *
- * @since 2.1
- */
-// TODO(beder): Reduce the visibility of this class to package-private.
-@Beta
-public final class TimingRecorders {
- private static final Logger logger = Logger.getLogger(TimingRecorders.class.getName());
-
- /**
- * Returns a timing recorder factory that delegates to the given factories, and ensures that any
- * method called on this object, even transitively, does not throw a {@link RuntimeException} or
- * return null.
- *
- * <p>If the delegate recorders throw an {@link Error}, then that will escape this recorder
- * implementation. Errors are treated as unrecoverable conditions, and may cause the entire
- * component's execution to fail.
- */
- public static ProductionComponentTimingRecorder.Factory
- delegatingProductionComponentTimingRecorderFactory(
- Collection<ProductionComponentTimingRecorder.Factory> factories) {
- switch (factories.size()) {
- case 0:
- return noOpProductionComponentTimingRecorderFactory();
- case 1:
- return new NonThrowingProductionComponentTimingRecorder.Factory(
- Iterables.getOnlyElement(factories));
- default:
- return new DelegatingProductionComponentTimingRecorder.Factory(factories);
- }
- }
-
- /**
- * A component recorder that delegates to a single recorder, and catches and logs all exceptions
- * that the delegate throws.
- */
- private static final class NonThrowingProductionComponentTimingRecorder
- implements ProductionComponentTimingRecorder {
- private final ProductionComponentTimingRecorder delegate;
-
- NonThrowingProductionComponentTimingRecorder(ProductionComponentTimingRecorder delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
- try {
- ProducerTimingRecorder recorder = delegate.producerTimingRecorderFor(token);
- return recorder == null
- ? ProducerTimingRecorder.noOp()
- : new NonThrowingProducerTimingRecorder(recorder);
- } catch (RuntimeException e) {
- logProducerTimingRecorderForException(e, delegate, token);
- return ProducerTimingRecorder.noOp();
- }
- }
-
- static final class Factory implements ProductionComponentTimingRecorder.Factory {
- private final ProductionComponentTimingRecorder.Factory delegate;
-
- Factory(ProductionComponentTimingRecorder.Factory delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public ProductionComponentTimingRecorder create(Object component) {
- try {
- ProductionComponentTimingRecorder recorder = delegate.create(component);
- return recorder == null
- ? noOpProductionComponentTimingRecorder()
- : new NonThrowingProductionComponentTimingRecorder(recorder);
- } catch (RuntimeException e) {
- logCreateException(e, delegate, component);
- return noOpProductionComponentTimingRecorder();
- }
- }
- }
- }
-
- /**
- * A producer recorder that delegates to a single recorder, and catches and logs all exceptions
- * that the delegate throws.
- */
- private static final class NonThrowingProducerTimingRecorder extends ProducerTimingRecorder {
- private final ProducerTimingRecorder delegate;
-
- NonThrowingProducerTimingRecorder(ProducerTimingRecorder delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void recordMethod(long startedNanos, long durationNanos) {
- try {
- delegate.recordMethod(startedNanos, durationNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordMethod");
- }
- }
-
- @Override
- public void recordSuccess(long latencyNanos) {
- try {
- delegate.recordSuccess(latencyNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordSuccess");
- }
- }
-
- @Override
- public void recordFailure(Throwable exception, long latencyNanos) {
- try {
- delegate.recordFailure(exception, latencyNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordFailure");
- }
- }
-
- @Override
- public void recordSkip(Throwable exception) {
- try {
- delegate.recordSkip(exception);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordSkip");
- }
- }
- }
-
- /**
- * A component recorder that delegates to several recorders, and catches and logs all exceptions
- * that the delegates throw.
- */
- private static final class DelegatingProductionComponentTimingRecorder
- implements ProductionComponentTimingRecorder {
- private final ImmutableList<ProductionComponentTimingRecorder> delegates;
-
- DelegatingProductionComponentTimingRecorder(
- ImmutableList<ProductionComponentTimingRecorder> delegates) {
- this.delegates = delegates;
- }
-
- @Override
- public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
- ImmutableList.Builder<ProducerTimingRecorder> recordersBuilder = ImmutableList.builder();
- for (ProductionComponentTimingRecorder delegate : delegates) {
- try {
- ProducerTimingRecorder recorder = delegate.producerTimingRecorderFor(token);
- if (recorder != null) {
- recordersBuilder.add(recorder);
- }
- } catch (RuntimeException e) {
- logProducerTimingRecorderForException(e, delegate, token);
- }
- }
- ImmutableList<ProducerTimingRecorder> recorders = recordersBuilder.build();
- switch (recorders.size()) {
- case 0:
- return ProducerTimingRecorder.noOp();
- case 1:
- return new NonThrowingProducerTimingRecorder(Iterables.getOnlyElement(recorders));
- default:
- return new DelegatingProducerTimingRecorder(recorders);
- }
- }
-
- static final class Factory implements ProductionComponentTimingRecorder.Factory {
- private final ImmutableList<? extends ProductionComponentTimingRecorder.Factory> delegates;
-
- Factory(Iterable<? extends ProductionComponentTimingRecorder.Factory> delegates) {
- this.delegates = ImmutableList.copyOf(delegates);
- }
-
- @Override
- public ProductionComponentTimingRecorder create(Object component) {
- ImmutableList.Builder<ProductionComponentTimingRecorder> recordersBuilder =
- ImmutableList.builder();
- for (ProductionComponentTimingRecorder.Factory delegate : delegates) {
- try {
- ProductionComponentTimingRecorder recorder = delegate.create(component);
- if (recorder != null) {
- recordersBuilder.add(recorder);
- }
- } catch (RuntimeException e) {
- logCreateException(e, delegate, component);
- }
- }
- ImmutableList<ProductionComponentTimingRecorder> recorders = recordersBuilder.build();
- switch (recorders.size()) {
- case 0:
- return noOpProductionComponentTimingRecorder();
- case 1:
- return new NonThrowingProductionComponentTimingRecorder(
- Iterables.getOnlyElement(recorders));
- default:
- return new DelegatingProductionComponentTimingRecorder(recorders);
- }
- }
- }
- }
-
- /**
- * A producer recorder that delegates to several recorders, and catches and logs all exceptions
- * that the delegates throw.
- */
- private static final class DelegatingProducerTimingRecorder extends ProducerTimingRecorder {
- private final ImmutableList<ProducerTimingRecorder> delegates;
-
- DelegatingProducerTimingRecorder(ImmutableList<ProducerTimingRecorder> delegates) {
- this.delegates = delegates;
- }
-
- @Override
- public void recordMethod(long startedNanos, long durationNanos) {
- for (ProducerTimingRecorder delegate : delegates) {
- try {
- delegate.recordMethod(startedNanos, durationNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordMethod");
- }
- }
- }
-
- @Override
- public void recordSuccess(long latencyNanos) {
- for (ProducerTimingRecorder delegate : delegates) {
- try {
- delegate.recordSuccess(latencyNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordSuccess");
- }
- }
- }
-
- @Override
- public void recordFailure(Throwable exception, long latencyNanos) {
- for (ProducerTimingRecorder delegate : delegates) {
- try {
- delegate.recordFailure(exception, latencyNanos);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordFailure");
- }
- }
- }
-
- @Override
- public void recordSkip(Throwable exception) {
- for (ProducerTimingRecorder delegate : delegates) {
- try {
- delegate.recordSkip(exception);
- } catch (RuntimeException e) {
- logProducerTimingRecorderMethodException(e, delegate, "recordSkip");
- }
- }
- }
- }
-
- /** Returns a recorder factory that returns no-op component recorders. */
- public static ProductionComponentTimingRecorder.Factory
- noOpProductionComponentTimingRecorderFactory() {
- return NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER_FACTORY;
- }
-
- /** Returns a component recorder that returns no-op producer recorders. */
- public static ProductionComponentTimingRecorder noOpProductionComponentTimingRecorder() {
- return NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER;
- }
-
- private static final ProductionComponentTimingRecorder.Factory
- NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER_FACTORY =
- new ProductionComponentTimingRecorder.Factory() {
- @Override
- public ProductionComponentTimingRecorder create(Object component) {
- return noOpProductionComponentTimingRecorder();
- }
- };
-
- private static final ProductionComponentTimingRecorder
- NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER =
- new ProductionComponentTimingRecorder() {
- @Override
- public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
- return ProducerTimingRecorder.noOp();
- }
- };
-
- private static void logCreateException(
- RuntimeException e, ProductionComponentTimingRecorder.Factory factory, Object component) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProductionComponentTimingRecorder.Factory.create on"
- + " factory "
- + factory
- + " with component "
- + component,
- e);
- }
-
- private static void logProducerTimingRecorderForException(
- RuntimeException e, ProductionComponentTimingRecorder recorder, ProducerToken token) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProductionComponentTimingRecorder.producerTimingRecorderFor"
- + "on recorder "
- + recorder
- + " with token "
- + token,
- e);
- }
-
- private static void logProducerTimingRecorderMethodException(
- RuntimeException e, ProducerTimingRecorder recorder, String method) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProducerTimingRecorder."
- + method
- + " on recorder "
- + recorder,
- e);
- }
-
- private TimingRecorders() {}
-}
diff --git a/java/dagger/producers/monitoring/internal/Monitors.java b/java/dagger/producers/monitoring/internal/Monitors.java
deleted file mode 100644
index 13b438a..0000000
--- a/java/dagger/producers/monitoring/internal/Monitors.java
+++ /dev/null
@@ -1,387 +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.producers.monitoring.internal;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.Collection;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.inject.Provider;
-
-/**
- * Utility methods relating to monitoring, for use in generated producers code.
- */
-public final class Monitors {
- private static final Logger logger = Logger.getLogger(Monitors.class.getName());
-
- /**
- * Returns a monitor factory that delegates to the given factories, and ensures that any method
- * called on this object, even transitively, does not throw a {@link RuntimeException} or return
- * null.
- *
- * <p>If the delegate monitors throw an {@link Error}, then that will escape this monitor
- * implementation. Errors are treated as unrecoverable conditions, and may cause the entire
- * component's execution to fail.
- */
- public static ProductionComponentMonitor.Factory delegatingProductionComponentMonitorFactory(
- Collection<? extends ProductionComponentMonitor.Factory> factories) {
- if (factories.isEmpty()) {
- return ProductionComponentMonitor.Factory.noOp();
- } else if (factories.size() == 1) {
- return new NonThrowingProductionComponentMonitor.Factory(Iterables.getOnlyElement(factories));
- } else {
- return new DelegatingProductionComponentMonitor.Factory(factories);
- }
- }
-
- /**
- * Creates a new monitor for the given component, from a set of monitor factories. This will not
- * throw a {@link RuntimeException} or return null.
- */
- public static ProductionComponentMonitor createMonitorForComponent(
- Provider<?> componentProvider,
- Provider<Set<ProductionComponentMonitor.Factory>> monitorFactorySetProvider) {
- try {
- ProductionComponentMonitor.Factory factory =
- delegatingProductionComponentMonitorFactory(monitorFactorySetProvider.get());
- return factory.create(componentProvider.get());
- } catch (RuntimeException e) {
- logger.log(Level.SEVERE, "RuntimeException while constructing monitor factories.", e);
- return ProductionComponentMonitor.noOp();
- }
- }
-
- /**
- * A component monitor that delegates to a single monitor, and catches and logs all exceptions
- * that the delegate throws.
- */
- private static final class NonThrowingProductionComponentMonitor
- extends ProductionComponentMonitor {
- private final ProductionComponentMonitor delegate;
-
- NonThrowingProductionComponentMonitor(ProductionComponentMonitor delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- try {
- ProducerMonitor monitor = delegate.producerMonitorFor(token);
- return monitor == null ? ProducerMonitor.noOp() : new NonThrowingProducerMonitor(monitor);
- } catch (RuntimeException e) {
- logProducerMonitorForException(e, delegate, token);
- return ProducerMonitor.noOp();
- }
- }
-
- static final class Factory extends ProductionComponentMonitor.Factory {
- private final ProductionComponentMonitor.Factory delegate;
-
- Factory(ProductionComponentMonitor.Factory delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public ProductionComponentMonitor create(Object component) {
- try {
- ProductionComponentMonitor monitor = delegate.create(component);
- return monitor == null
- ? ProductionComponentMonitor.noOp()
- : new NonThrowingProductionComponentMonitor(monitor);
- } catch (RuntimeException e) {
- logCreateException(e, delegate, component);
- return ProductionComponentMonitor.noOp();
- }
- }
- }
- }
-
- /**
- * A producer monitor that delegates to a single monitor, and catches and logs all exceptions
- * that the delegate throws.
- */
- private static final class NonThrowingProducerMonitor extends ProducerMonitor {
- private final ProducerMonitor delegate;
-
- NonThrowingProducerMonitor(ProducerMonitor delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void requested() {
- try {
- delegate.requested();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "requested");
- }
- }
-
- @Override
- public void ready() {
- try {
- delegate.ready();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "ready");
- }
- }
-
- @Override
- public void methodStarting() {
- try {
- delegate.methodStarting();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "methodStarting");
- }
- }
-
- @Override
- public void methodFinished() {
- try {
- delegate.methodFinished();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "methodFinished");
- }
- }
-
- @Override
- public void succeeded(Object o) {
- try {
- delegate.succeeded(o);
- } catch (RuntimeException e) {
- logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
- }
- }
-
- @Override
- public void failed(Throwable t) {
- try {
- delegate.failed(t);
- } catch (RuntimeException e) {
- logProducerMonitorArgMethodException(e, delegate, "failed", t);
- }
- }
- }
-
- /**
- * A component monitor that delegates to several monitors, and catches and logs all exceptions
- * that the delegates throw.
- */
- private static final class DelegatingProductionComponentMonitor
- extends ProductionComponentMonitor {
- private final ImmutableList<ProductionComponentMonitor> delegates;
-
- DelegatingProductionComponentMonitor(ImmutableList<ProductionComponentMonitor> delegates) {
- this.delegates = delegates;
- }
-
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- ImmutableList.Builder<ProducerMonitor> monitorsBuilder = ImmutableList.builder();
- for (ProductionComponentMonitor delegate : delegates) {
- try {
- ProducerMonitor monitor = delegate.producerMonitorFor(token);
- if (monitor != null) {
- monitorsBuilder.add(monitor);
- }
- } catch (RuntimeException e) {
- logProducerMonitorForException(e, delegate, token);
- }
- }
- ImmutableList<ProducerMonitor> monitors = monitorsBuilder.build();
- if (monitors.isEmpty()) {
- return ProducerMonitor.noOp();
- } else if (monitors.size() == 1) {
- return new NonThrowingProducerMonitor(Iterables.getOnlyElement(monitors));
- } else {
- return new DelegatingProducerMonitor(monitors);
- }
- }
-
- static final class Factory extends ProductionComponentMonitor.Factory {
- private final ImmutableList<? extends ProductionComponentMonitor.Factory> delegates;
-
- Factory(Iterable<? extends ProductionComponentMonitor.Factory> delegates) {
- this.delegates = ImmutableList.copyOf(delegates);
- }
-
- @Override
- public ProductionComponentMonitor create(Object component) {
- ImmutableList.Builder<ProductionComponentMonitor> monitorsBuilder = ImmutableList.builder();
- for (ProductionComponentMonitor.Factory delegate : delegates) {
- try {
- ProductionComponentMonitor monitor = delegate.create(component);
- if (monitor != null) {
- monitorsBuilder.add(monitor);
- }
- } catch (RuntimeException e) {
- logCreateException(e, delegate, component);
- }
- }
- ImmutableList<ProductionComponentMonitor> monitors = monitorsBuilder.build();
- if (monitors.isEmpty()) {
- return ProductionComponentMonitor.noOp();
- } else if (monitors.size() == 1) {
- return new NonThrowingProductionComponentMonitor(Iterables.getOnlyElement(monitors));
- } else {
- return new DelegatingProductionComponentMonitor(monitors);
- }
- }
- }
- }
-
- /**
- * A producer monitor that delegates to several monitors, and catches and logs all exceptions
- * that the delegates throw.
- */
- private static final class DelegatingProducerMonitor extends ProducerMonitor {
- private final ImmutableList<ProducerMonitor> delegates;
-
- DelegatingProducerMonitor(ImmutableList<ProducerMonitor> delegates) {
- this.delegates = delegates;
- }
-
- @Override
- public void requested() {
- for (ProducerMonitor delegate : delegates) {
- try {
- delegate.requested();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "requested");
- }
- }
- }
-
- @Override
- public void ready() {
- for (ProducerMonitor delegate : delegates) {
- try {
- delegate.ready();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "ready");
- }
- }
- }
-
- @Override
- public void methodStarting() {
- for (ProducerMonitor delegate : delegates) {
- try {
- delegate.methodStarting();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "methodStarting");
- }
- }
- }
-
- @Override
- public void methodFinished() {
- for (ProducerMonitor delegate : delegates.reverse()) {
- try {
- delegate.methodFinished();
- } catch (RuntimeException e) {
- logProducerMonitorMethodException(e, delegate, "methodFinished");
- }
- }
- }
-
- @Override
- public void succeeded(Object o) {
- for (ProducerMonitor delegate : delegates.reverse()) {
- try {
- delegate.succeeded(o);
- } catch (RuntimeException e) {
- logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
- }
- }
- }
-
- @Override
- public void failed(Throwable t) {
- for (ProducerMonitor delegate : delegates.reverse()) {
- try {
- delegate.failed(t);
- } catch (RuntimeException e) {
- logProducerMonitorArgMethodException(e, delegate, "failed", t);
- }
- }
- }
- }
-
- /** Returns a provider of a no-op component monitor. */
- public static Provider<ProductionComponentMonitor> noOpProductionComponentMonitorProvider() {
- return NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER;
- }
-
- private static final Provider<ProductionComponentMonitor>
- NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER =
- new Provider<ProductionComponentMonitor>() {
- @Override
- public ProductionComponentMonitor get() {
- return ProductionComponentMonitor.noOp();
- }
- };
-
- private static void logCreateException(
- RuntimeException e, ProductionComponentMonitor.Factory factory, Object component) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProductionComponentMonitor.Factory.create on factory "
- + factory
- + " with component "
- + component,
- e);
- }
-
- private static void logProducerMonitorForException(
- RuntimeException e, ProductionComponentMonitor monitor, ProducerToken token) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProductionComponentMonitor.producerMonitorFor on monitor "
- + monitor
- + " with token "
- + token,
- e);
- }
-
- private static void logProducerMonitorMethodException(
- RuntimeException e, ProducerMonitor monitor, String method) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProducerMonitor." + method + " on monitor " + monitor,
- e);
- }
-
- private static void logProducerMonitorArgMethodException(
- RuntimeException e, ProducerMonitor monitor, String method, Object arg) {
- logger.log(
- Level.SEVERE,
- "RuntimeException while calling ProducerMonitor."
- + method
- + " on monitor "
- + monitor
- + " with "
- + arg,
- e);
- }
-
- private Monitors() {}
-}
diff --git a/java/dagger/producers/monitoring/package-info.java b/java/dagger/producers/monitoring/package-info.java
deleted file mode 100644
index 122df5d..0000000
--- a/java/dagger/producers/monitoring/package-info.java
+++ /dev/null
@@ -1,24 +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.
- */
-
-/**
- * This package provides hooks for monitoring producers.
- *
- * <p>The interfaces in this package are not stable. Do not use these interfaces unless you are
- * prepared to be broken.
- */
-
-package dagger.producers.monitoring;
diff --git a/java/dagger/producers/package-info.java b/java/dagger/producers/package-info.java
deleted file mode 100644
index 9693ae9..0000000
--- a/java/dagger/producers/package-info.java
+++ /dev/null
@@ -1,26 +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 public API for Dagger 2's producer functionality.
- *
- * <p>Dagger Producers is an extension to Dagger that implements asynchronous dependency injection
- * in Java.
- *
- * <p>Extended documentation on Dagger Producers can be found at <a
- * href="https://dagger.dev/producers">https://dagger.dev/producers</a>.
- */
-package dagger.producers;
diff --git a/java/dagger/spi/BUILD b/java/dagger/spi/BUILD
deleted file mode 100644
index 9c04582..0000000
--- a/java/dagger/spi/BUILD
+++ /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.
-
-# Description:
-# The Service Provider Interface for Dagger's binding graph model
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-
-filegroup(
- name = "spi-srcs",
- srcs = glob(["*.java"]),
-)
-
-load("//tools:maven.bzl", "POM_VERSION", "pom_file")
-
-java_library(
- name = "spi",
- srcs = [":spi-srcs"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- tags = ["maven_coordinates=com.google.dagger:dagger-spi:" + POM_VERSION],
- deps = [
- "//java/dagger:core",
- "//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",
- ],
-)
-
-pom_file(
- name = "pom",
- artifact_id = "dagger-spi",
- artifact_name = "Dagger SPI",
- targets = [
- "//java/dagger/model",
- ":spi",
- ],
-)
diff --git a/java/dagger/spi/BindingGraphPlugin.java b/java/dagger/spi/BindingGraphPlugin.java
deleted file mode 100644
index 02a051b..0000000
--- a/java/dagger/spi/BindingGraphPlugin.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.spi;
-
-import dagger.model.BindingGraph;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-
-/**
- * A pluggable visitor for {@link BindingGraph}.
- *
- * <p>Note: This is still experimental and will change.
- */
-public interface BindingGraphPlugin {
- /**
- * Called once for each valid root binding graph encountered by the Dagger processor. May report
- * diagnostics using {@code diagnosticReporter}.
- */
- void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter);
-
- /**
- * Initializes this plugin with a {@link Filer} that it can use to write Java or other files based
- * on the binding graph. This will be called once per instance of this plugin, before any graph is
- * {@linkplain #visitGraph(BindingGraph, DiagnosticReporter) visited}.
- *
- * @see javax.annotation.processing.ProcessingEnvironment#getFiler()
- */
- default void initFiler(Filer filer) {}
-
- /**
- * Initializes this plugin with a {@link Types} instance. This will be called once per instance of
- * this plugin, before any graph is {@linkplain #visitGraph(BindingGraph, DiagnosticReporter)
- * visited}.
- *
- * @see javax.annotation.processing.ProcessingEnvironment#getTypeUtils()
- */
- default void initTypes(Types types) {}
-
- /**
- * Initializes this plugin with a {@link Elements} instance. This will be called once per instance
- * of this plugin, before any graph is {@linkplain #visitGraph(BindingGraph, DiagnosticReporter)
- * visited}.
- *
- * @see javax.annotation.processing.ProcessingEnvironment#getElementUtils()
- */
- default void initElements(Elements elements) {}
-
- /**
- * Initializes this plugin with a filtered view of the options passed on the {@code javac}
- * command-line for all keys from {@link #supportedOptions()}. This will be called once per
- * instance of this plugin, before any graph is {@linkplain #visitGraph(BindingGraph,
- * DiagnosticReporter) visited}.
- *
- * @see javax.annotation.processing.ProcessingEnvironment#getOptions()
- */
- default void initOptions(Map<String, String> options) {}
-
- /**
- * Returns the annotation-processing options that this plugin uses to configure behavior.
- *
- * @see javax.annotation.processing.Processor#getSupportedOptions()
- */
- default Set<String> supportedOptions() {
- return Collections.emptySet();
- }
-
- /**
- * A distinguishing name of the plugin that will be used in diagnostics printed to the {@link
- * Messager}. By default, the {@linkplain Class#getCanonicalName() fully qualified name} of the
- * plugin is used.
- */
- default String pluginName() {
- return getClass().getCanonicalName();
- }
-}
diff --git a/java/dagger/spi/DiagnosticReporter.java b/java/dagger/spi/DiagnosticReporter.java
deleted file mode 100644
index f9ec41e..0000000
--- a/java/dagger/spi/DiagnosticReporter.java
+++ /dev/null
@@ -1,103 +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.spi;
-
-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 javax.tools.Diagnostic;
-
-/**
- * An object that {@link BindingGraphPlugin}s can use to report diagnostics while visiting a {@link
- * BindingGraph}.
- *
- * <p>Note: This API is still experimental and will change.
- */
-public interface DiagnosticReporter {
- /**
- * Reports a diagnostic for a component. For non-root components, includes information about the
- * path from the root component.
- */
- void reportComponent(Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message);
-
- /**
- * Reports a diagnostic for a component. For non-root components, includes information about the
- * path from the root component.
- */
- @FormatMethod
- void reportComponent(
- Diagnostic.Kind diagnosticKind,
- ComponentNode componentNode,
- String messageFormat,
- Object firstArg,
- Object... moreArgs);
-
- /**
- * Reports a diagnostic for a binding or missing binding. Includes information about how the
- * binding is reachable from entry points.
- */
- void reportBinding(Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message);
-
- /**
- * Reports a diagnostic for a binding or missing binding. Includes information about how the
- * binding is reachable from entry points.
- */
- @FormatMethod
- void reportBinding(
- Diagnostic.Kind diagnosticKind,
- MaybeBinding binding,
- String messageFormat,
- Object firstArg,
- Object... moreArgs);
-
- /**
- * Reports a diagnostic for a dependency. Includes information about how the dependency is
- * reachable from entry points.
- */
- void reportDependency(
- Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message);
-
- /**
- * Reports a diagnostic for a dependency. Includes information about how the dependency is
- * reachable from entry points.
- */
- @FormatMethod
- void reportDependency(
- Diagnostic.Kind diagnosticKind,
- DependencyEdge dependencyEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs);
-
- /** Reports a diagnostic for a subcomponent factory method. */
- void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String message);
-
- /** Reports a diagnostic for a subcomponent factory method. */
- @FormatMethod
- void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs);
-}
diff --git a/java/dagger/spi/package-info.java b/java/dagger/spi/package-info.java
deleted file mode 100644
index 87ebb33..0000000
--- a/java/dagger/spi/package-info.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.
- */
-
-/**
- * This package contains the Service Provider interface (SPI) to the {@link dagger.model} APIs at
- * annotation-processing-time.
- *
- * <p>This package is experimental, and APIs may change at over time.
- */
-@CheckReturnValue
-@Beta
-package dagger.spi;
-
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.Beta;
diff --git a/javatests/dagger/BUILD b/javatests/dagger/BUILD
deleted file mode 100644
index 3debec5..0000000
--- a/javatests/dagger/BUILD
+++ /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.
-
-# 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")
-
-GenJavaTests(
- name = "core_tests",
- srcs = glob(["**/*.java"]),
- functional = 0,
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "//java/dagger:core",
- "@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
deleted file mode 100644
index 19b6e84..0000000
--- a/javatests/dagger/android/AndroidInjectionTest.java
+++ /dev/null
@@ -1,201 +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.android;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import android.app.Activity;
-import android.app.Application;
-import android.app.Fragment;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.FragmentTestUtil;
-
-@Config(manifest = Config.NONE)
-@RunWith(RobolectricTestRunner.class)
-public final class AndroidInjectionTest {
-
- // Most positive tests are performed in javatests/dagger/android/support/functional, but
- // Robolectric's support for framework fragments is lacking, so we supplement those tests here:
- public static class InjectableFragment extends Fragment {
- String tag;
- }
-
- private static AndroidInjector<Fragment> fakeFragmentInjector(String tag) {
- return instance -> {
- if (instance instanceof InjectableFragment) {
- ((InjectableFragment) instance).tag = tag;
- }
- };
- }
-
- public static class ApplicationInjectsFragment extends Application
- implements HasFragmentInjector {
- @Override
- public AndroidInjector<Fragment> fragmentInjector() {
- return fakeFragmentInjector("injected by app");
- }
- }
-
- @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
- @Test
- public void fragmentInjectedByApplication() {
- Activity activity = Robolectric.setupActivity(Activity.class);
- InjectableFragment fragment = new InjectableFragment();
- activity.getFragmentManager().beginTransaction().add(fragment, "tag").commit();
-
- AndroidInjection.inject(fragment);
-
- assertThat(fragment.tag).isEqualTo("injected by app");
- }
-
- public static class ActivityInjectsFragment extends Activity implements HasFragmentInjector {
- @Override
- public AndroidInjector<Fragment> fragmentInjector() {
- return fakeFragmentInjector("injected by activity");
- }
- }
-
- @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
- @Test
- public void fragmentInjectedByActivity() {
- ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class);
- InjectableFragment fragment = new InjectableFragment();
- activity.getFragmentManager().beginTransaction().add(fragment, "tag").commit();
-
- AndroidInjection.inject(fragment);
-
- assertThat(fragment.tag).isEqualTo("injected by activity");
- }
-
- public static class ParentFragmentInjectsChildFragment extends Fragment
- implements HasFragmentInjector {
- @Override
- public AndroidInjector<Fragment> fragmentInjector() {
- return fakeFragmentInjector("injected by parent fragment");
- }
- }
-
- @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
- @Test
- public void fragmentInjectedByParentFragment() {
- ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class);
- ParentFragmentInjectsChildFragment parentFragment = new ParentFragmentInjectsChildFragment();
- InjectableFragment childFragment = new InjectableFragment();
-
- activity.getFragmentManager().beginTransaction().add(parentFragment, "tag").commit();
- parentFragment
- .getChildFragmentManager()
- .beginTransaction()
- .add(childFragment, "child-tag")
- .commit();
- AndroidInjection.inject(childFragment);
-
- assertThat(childFragment.tag).isEqualTo("injected by parent fragment");
- }
-
- @Test
- public void injectActivity_applicationDoesntImplementHasActivityInjector() {
- Activity activity = Robolectric.setupActivity(Activity.class);
-
- try {
- AndroidInjection.inject(activity);
- fail();
- } catch (Exception e) {
- assertThat(e)
- .hasMessageThat()
- .contains("Application does not implement dagger.android.HasAndroidInjector");
- }
- }
-
- @Test
- public void injectFragment_hasFragmentInjectorNotFound() {
- Fragment fragment = new Fragment();
- FragmentTestUtil.startFragment(fragment);
-
- try {
- AndroidInjection.inject(fragment);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessageThat().contains("No injector was found");
- }
- }
-
- private static class ApplicationReturnsNull extends Application
- implements HasActivityInjector, HasFragmentInjector {
- @Override
- public AndroidInjector<Activity> activityInjector() {
- return null;
- }
-
- @Override
- public AndroidInjector<Fragment> fragmentInjector() {
- return null;
- }
- }
-
- @Test
- @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
- public void activityInjector_returnsNull() {
- Activity activity = Robolectric.setupActivity(Activity.class);
-
- try {
- AndroidInjection.inject(activity);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessageThat().contains("activityInjector() returned null");
- }
- }
-
- @Test
- @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
- public void fragmentInjector_returnsNull() {
- Fragment fragment = new Fragment();
- FragmentTestUtil.startFragment(fragment);
-
- try {
- AndroidInjection.inject(fragment);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessageThat().contains("fragmentInjector() returned null");
- }
- }
-
- @Test
- public void injectActivity_nullInput() {
- try {
- AndroidInjection.inject((Activity) null);
- fail();
- } catch (NullPointerException e) {
- assertThat(e).hasMessageThat().contains("activity");
- }
- }
-
- @Test
- public void injectFragment_nullInput() {
- try {
- AndroidInjection.inject((Fragment) null);
- fail();
- } catch (NullPointerException e) {
- assertThat(e).hasMessageThat().contains("fragment");
- }
- }
-}
diff --git a/javatests/dagger/android/BUILD b/javatests/dagger/android/BUILD
deleted file mode 100644
index 5bc3f45..0000000
--- a/javatests/dagger/android/BUILD
+++ /dev/null
@@ -1,36 +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 for Dagger's Android integrations
-
-package(default_visibility = ["//:src"])
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenRobolectricTests")
-
-GenRobolectricTests(
- name = "android_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- manifest_values = {"minSdkVersion": "17"},
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/android",
- "@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
deleted file mode 100644
index d0306b8..0000000
--- a/javatests/dagger/android/DispatchingAndroidInjectorTest.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.android;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import android.app.Activity;
-import com.google.common.collect.ImmutableMap;
-import dagger.android.AndroidInjector.Factory;
-import dagger.android.DispatchingAndroidInjector.InvalidInjectorBindingException;
-import java.util.Map;
-import javax.inject.Provider;
-import org.junit.Test;
-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
- public void withClassKeys() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(
- ImmutableMap.of(FooActivity.class, FooInjector.Factory::new), ImmutableMap.of());
-
- FooActivity activity = Robolectric.setupActivity(FooActivity.class);
- assertThat(dispatchingAndroidInjector.maybeInject(activity)).isTrue();
- }
-
- @Test
- public void withStringKeys() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(
- ImmutableMap.of(),
- ImmutableMap.of(FooActivity.class.getName(), FooInjector.Factory::new));
-
- FooActivity activity = Robolectric.setupActivity(FooActivity.class);
- assertThat(dispatchingAndroidInjector.maybeInject(activity)).isTrue();
- }
-
- @Test
- public void withMixedKeys() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(
- ImmutableMap.of(FooActivity.class, FooInjector.Factory::new),
- ImmutableMap.of(BarActivity.class.getName(), BarInjector.Factory::new));
-
- FooActivity fooActivity = Robolectric.setupActivity(FooActivity.class);
- assertThat(dispatchingAndroidInjector.maybeInject(fooActivity)).isTrue();
- BarActivity barActivity = Robolectric.setupActivity(BarActivity.class);
- assertThat(dispatchingAndroidInjector.maybeInject(barActivity)).isTrue();
- }
-
- @Test
- public void maybeInject_returnsFalse_ifNoMatchingInjectorExists() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(ImmutableMap.of(), ImmutableMap.of());
-
- BarActivity activity = Robolectric.setupActivity(BarActivity.class);
- assertThat(dispatchingAndroidInjector.maybeInject(activity)).isFalse();
- }
-
- @Test
- public void throwsIfFactoryCreateReturnsNull() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(
- ImmutableMap.of(FooActivity.class, () -> null), ImmutableMap.of());
- FooActivity activity = Robolectric.setupActivity(FooActivity.class);
-
- try {
- dispatchingAndroidInjector.maybeInject(activity);
- fail("Expected NullPointerException");
- } catch (NullPointerException expected) {
- }
- }
-
- @Test
- public void throwsIfClassMismatched() {
- DispatchingAndroidInjector<Activity> dispatchingAndroidInjector =
- newDispatchingAndroidInjector(
- ImmutableMap.of(FooActivity.class, BarInjector.Factory::new), ImmutableMap.of());
- FooActivity activity = Robolectric.setupActivity(FooActivity.class);
-
- try {
- dispatchingAndroidInjector.maybeInject(activity);
- fail("Expected InvalidInjectorBindingException");
- } catch (InvalidInjectorBindingException expected) {
- }
- }
-
- private static <T> DispatchingAndroidInjector<T> newDispatchingAndroidInjector(
- Map<Class<?>, Provider<Factory<?>>> injectorFactoriesWithClassKeys,
- Map<String, Provider<AndroidInjector.Factory<?>>>
- injectorFactoriesWithStringKeys) {
- return new DispatchingAndroidInjector<>(
- injectorFactoriesWithClassKeys,
- injectorFactoriesWithStringKeys ,
- ImmutableMap.of(),
- ImmutableMap.of());
- }
-
- static class FooActivity extends Activity {}
-
- static class BarActivity extends Activity {}
-
- static class FooInjector implements AndroidInjector<FooActivity> {
- @Override
- public void inject(FooActivity instance) {}
-
- static class Factory implements AndroidInjector.Factory<FooActivity> {
- @Override
- public AndroidInjector<FooActivity> create(FooActivity activity) {
- return new FooInjector();
- }
- }
- }
-
- static class BarInjector implements AndroidInjector<BarActivity> {
- @Override
- public void inject(BarActivity instance) {}
-
- static class Factory implements AndroidInjector.Factory<BarActivity> {
- @Override
- public AndroidInjector<BarActivity> create(BarActivity activity) {
- return new BarInjector();
- }
- }
- }
-}
diff --git a/javatests/dagger/android/processor/AndroidMapKeyValidatorTest.java b/javatests/dagger/android/processor/AndroidMapKeyValidatorTest.java
deleted file mode 100644
index cfa6e90..0000000
--- a/javatests/dagger/android/processor/AndroidMapKeyValidatorTest.java
+++ /dev/null
@@ -1,359 +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.android.processor;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-
-import com.google.common.base.Joiner;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.ComponentProcessor;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AndroidMapKeyValidatorTest {
- private static final JavaFileObject FOO_ACTIVITY =
- JavaFileObjects.forSourceLines(
- "test.FooActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "import dagger.android.AndroidInjector;",
- "",
- "public class FooActivity extends Activity {",
- " interface Factory extends AndroidInjector.Factory<FooActivity> {}",
- " abstract static class Builder extends AndroidInjector.Builder<FooActivity> {}",
- "}");
- private static final JavaFileObject BAR_ACTIVITY =
- JavaFileObjects.forSourceLines(
- "test.BarActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "",
- "public class BarActivity extends Activity {}");
-
- private static JavaFileObject moduleWithMethod(String... lines) {
- return JavaFileObjects.forSourceLines(
- "test.AndroidModule",
- "package test;",
- "",
- "import android.app.Activity;",
- "import android.app.Fragment;",
- "import dagger.Module;",
- "import dagger.*;",
- "import dagger.android.*;",
- "import dagger.multibindings.*;",
- "import javax.inject.*;",
- "",
- "@Module",
- "abstract class AndroidModule {",
- " " + Joiner.on("\n ").join(lines),
- "}");
- }
-
- // TODO(dpb): Change these tests to use onLineContaining() instead of onLine().
- private static final int LINES_BEFORE_METHOD = 12;
-
- @Test
- public void rawFactoryType() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Factory bindRawFactory(FooActivity.Factory factory);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "should bind dagger.android.AndroidInjector.Factory<?>, "
- + "not dagger.android.AndroidInjector.Factory");
- }
-
- @Test
- public void rawBuilderType() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Builder bindRawBuilder(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "should bind dagger.android.AndroidInjector.Factory<?>, "
- + "not dagger.android.AndroidInjector.Builder");
- }
-
- @Test
- public void bindsToBuilderNotFactory() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Builder<?> bindBuilder(",
- " FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "should bind dagger.android.AndroidInjector.Factory<?>, not "
- + "dagger.android.AndroidInjector.Builder<?>");
- }
-
- @Test
- public void providesToBuilderNotFactory() {
- JavaFileObject module =
- moduleWithMethod(
- "@Provides",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "static AndroidInjector.Builder<?> bindBuilder(FooActivity.Builder builder) {",
- " return builder;",
- "}");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "should bind dagger.android.AndroidInjector.Factory<?>, not "
- + "dagger.android.AndroidInjector.Builder<?>");
- }
-
- @Test
- public void bindsToConcreteTypeInsteadOfWildcard() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Builder<FooActivity> bindBuilder(",
- " FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "should bind dagger.android.AndroidInjector.Factory<?>, not "
- + "dagger.android.AndroidInjector.Builder<test.FooActivity>");
- }
-
- @Test
- public void bindsToBaseTypeInsteadOfWildcard() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Builder<Activity> bindBuilder(",
- " FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Binds methods' parameter type must be assignable to the return type");
- }
-
- @Test
- public void bindsCorrectType() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Factory<?> bindCorrectType(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindsCorrectType_AndroidInjectionKey() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@AndroidInjectionKey(\"test.FooActivity\")",
- "abstract AndroidInjector.Factory<?> bindCorrectType(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindsCorrectType_AndroidInjectionKey_unbounded() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@AndroidInjectionKey(\"test.FooActivity\")",
- "abstract AndroidInjector.Factory<?> bindCorrectType(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindsWithScope() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "@Singleton",
- "abstract AndroidInjector.Factory<?> bindWithScope(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("should not be scoped");
- }
-
- @Test
- public void bindsWithScope_suppressWarnings() {
- JavaFileObject module =
- moduleWithMethod(
- "@SuppressWarnings(\"dagger.android.ScopedInjectorFactory\")",
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "@Singleton",
- "abstract AndroidInjector.Factory<?> bindWithScope(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void mismatchedMapKey_bindsFactory() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(BarActivity.class)",
- "abstract AndroidInjector.Factory<?> mismatchedFactory(FooActivity.Factory factory);");
- Compilation compilation = compile(module, FOO_ACTIVITY, BAR_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.FooActivity.Factory does not implement AndroidInjector<test.BarActivity>")
- .inFile(module)
- .onLine(LINES_BEFORE_METHOD + 3);
- }
-
- @Test
- public void mismatchedMapKey_bindsBuilder() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(BarActivity.class)",
- "abstract AndroidInjector.Factory<?> mismatchedBuilder(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY, BAR_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.FooActivity.Builder does not implement AndroidInjector<test.BarActivity>")
- .inFile(module)
- .onLine(LINES_BEFORE_METHOD + 3);
- }
-
- @Test
- public void mismatchedMapKey_bindsBuilder_androidInjectionKey() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@AndroidInjectionKey(\"test.BarActivity\")",
- "abstract AndroidInjector.Factory<?> mismatchedBuilder(FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY, BAR_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.FooActivity.Builder does not implement AndroidInjector<test.BarActivity>")
- .inFile(module)
- .onLine(LINES_BEFORE_METHOD + 3);
- }
-
- @Test
- public void mismatchedMapKey_providesBuilder() {
- JavaFileObject module =
- moduleWithMethod(
- "@Provides",
- "@IntoMap",
- "@ClassKey(BarActivity.class)",
- "static AndroidInjector.Factory<?> mismatchedBuilder(FooActivity.Builder builder) {",
- " return builder;",
- "}");
- Compilation compilation = compile(module, FOO_ACTIVITY, BAR_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindsQualifier_ignoresChecks() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "@Named(\"unused\")",
- // normally this should fail, since it is binding to a Builder not a Factory
- "abstract AndroidInjector.Builder<?> bindsBuilderWithQualifier(",
- " FooActivity.Builder builder);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindToPrimitive() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@AndroidInjectionKey(\"test.FooActivity\")",
- "abstract int bindInt(@Named(\"unused\") int otherInt);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void bindToNonFrameworkClass() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@AndroidInjectionKey(\"test.FooActivity\")",
- "abstract Number bindInt(Integer integer);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void invalidBindsMethod() {
- JavaFileObject module =
- moduleWithMethod(
- "@Binds",
- "@IntoMap",
- "@ClassKey(FooActivity.class)",
- "abstract AndroidInjector.Factory<?> bindCorrectType(",
- " FooActivity.Builder builder, FooActivity.Builder builder2);");
- Compilation compilation = compile(module, FOO_ACTIVITY);
- assertThat(compilation).failed();
- }
-
- private Compilation compile(JavaFileObject... files) {
- return javac().withProcessors(new ComponentProcessor(), new AndroidProcessor()).compile(files);
- }
-}
diff --git a/javatests/dagger/android/processor/AndroidProcessorTest.java b/javatests/dagger/android/processor/AndroidProcessorTest.java
deleted file mode 100644
index 1a45bdd..0000000
--- a/javatests/dagger/android/processor/AndroidProcessorTest.java
+++ /dev/null
@@ -1,81 +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.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
deleted file mode 100644
index 8a9c16e..0000000
--- a/javatests/dagger/android/processor/BUILD
+++ /dev/null
@@ -1,42 +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 for Dagger's Android integrations
-
-package(default_visibility = ["//:src"])
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
-
-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",
- ],
-)
diff --git a/javatests/dagger/android/processor/ContributesAndroidInjectorTest.java b/javatests/dagger/android/processor/ContributesAndroidInjectorTest.java
deleted file mode 100644
index 1718737..0000000
--- a/javatests/dagger/android/processor/ContributesAndroidInjectorTest.java
+++ /dev/null
@@ -1,214 +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.android.processor;
-
-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.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 ContributesAndroidInjectorTest {
- private static final JavaFileObject TEST_ACTIVITY =
- JavaFileObjects.forSourceLines(
- "test.TestActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "",
- "class TestActivity extends Activity {}");
-
- @Test
- public void notAbstract() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.android.ContributesAndroidInjector;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @ContributesAndroidInjector",
- " static TestActivity test() {",
- " return null;",
- " }",
- "}");
-
- Compilation compilation = compile(module, TEST_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("must be abstract")
- .inFile(module)
- .onLineContaining("test()");
- }
-
- @Test
- public void hasParameters() {
- JavaFileObject otherActivity =
- JavaFileObjects.forSourceLines(
- "test.OtherActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "",
- "class OtherActivity extends Activity {}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.android.ContributesAndroidInjector;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @ContributesAndroidInjector",
- " abstract TestActivity oneParam(TestActivity one);",
- "",
- " @ContributesAndroidInjector",
- " abstract OtherActivity manyParams(OtherActivity two, Object o);",
- "}");
-
- Compilation compilation = compile(module, TEST_ACTIVITY, otherActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cannot have parameters")
- .inFile(module)
- .onLineContaining("oneParam(");
- assertThat(compilation)
- .hadErrorContaining("cannot have parameters")
- .inFile(module)
- .onLineContaining("manyParams(");
- }
-
- @Test
- public void notInAModule() {
- JavaFileObject randomFile =
- JavaFileObjects.forSourceLines(
- "test.RandomFile",
- "package test;",
- "",
- "import dagger.android.ContributesAndroidInjector;",
- "",
- "abstract class RandomFile {",
- " @ContributesAndroidInjector",
- " abstract TestActivity test() {}",
- "}");
-
- Compilation compilation = compile(randomFile, TEST_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("must be in a @Module")
- .inFile(randomFile)
- .onLineContaining("test()");
- }
-
- @Test
- public void parameterizedReturnType() {
- JavaFileObject parameterizedActivity =
- JavaFileObjects.forSourceLines(
- "test.ParameterizedActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "",
- "class ParameterizedActivity<T> extends Activity {}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.android.ContributesAndroidInjector;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @ContributesAndroidInjector",
- " abstract <T> ParameterizedActivity<T> test();",
- "}");
-
- Compilation compilation = compile(module, TEST_ACTIVITY, parameterizedActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cannot return parameterized types")
- .inFile(module)
- .onLineContaining("test()");
- }
-
- @Test
- public void moduleIsntModule() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.android.ContributesAndroidInjector;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @ContributesAndroidInjector(modules = android.content.Intent.class)",
- " abstract TestActivity test();",
- "}");
-
- Compilation compilation = compile(module, TEST_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Intent is not a @Module")
- .inFile(module)
- .onLineContaining("modules = android.content.Intent.class");
- }
-
- @Test
- public void hasQualifier() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.android.ContributesAndroidInjector;",
- "import javax.inject.Qualifier;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Qualifier @interface AndroidQualifier {}",
- "",
- " @AndroidQualifier",
- " @ContributesAndroidInjector",
- " abstract TestActivity test();",
- "}");
-
- Compilation compilation = compile(module, TEST_ACTIVITY);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@ContributesAndroidInjector methods cannot have qualifiers")
- .inFile(module)
- .onLineContaining("@AndroidQualifier");
- }
-
- private static Compilation compile(JavaFileObject... javaFileObjects) {
- return javac().withProcessors(new AndroidProcessor()).compile(javaFileObjects);
- }
-}
diff --git a/javatests/dagger/android/processor/DuplicateAndroidInjectorsCheckerTest.java b/javatests/dagger/android/processor/DuplicateAndroidInjectorsCheckerTest.java
deleted file mode 100644
index a84c7eb..0000000
--- a/javatests/dagger/android/processor/DuplicateAndroidInjectorsCheckerTest.java
+++ /dev/null
@@ -1,106 +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.android.processor;
-
-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.JavaFileObjects;
-import dagger.internal.codegen.ComponentProcessor;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class DuplicateAndroidInjectorsCheckerTest {
- @Test
- public void conflictingMapKeys() {
- JavaFileObject activity =
- JavaFileObjects.forSourceLines(
- "test.TestActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "",
- "public class TestActivity extends Activity {}");
- JavaFileObject injectorFactory =
- JavaFileObjects.forSourceLines(
- "test.TestInjectorFactory",
- "package test;",
- "",
- "import dagger.android.AndroidInjector;",
- "import javax.inject.Inject;",
- "",
- "class TestInjectorFactory implements AndroidInjector.Factory<TestActivity> {",
- " @Inject TestInjectorFactory() {}",
- "",
- " @Override",
- " public AndroidInjector<TestActivity> create(TestActivity instance) { return null; }",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import android.app.Activity;",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.android.*;",
- "import dagger.multibindings.*;",
- "",
- "@Module",
- "interface TestModule {",
- " @Binds",
- " @IntoMap",
- " @ClassKey(TestActivity.class)",
- " AndroidInjector.Factory<?> classKey(TestInjectorFactory factory);",
- "",
- " @Binds",
- " @IntoMap",
- " @AndroidInjectionKey(\"test.TestActivity\")",
- " AndroidInjector.Factory<?> stringKey(TestInjectorFactory factory);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import android.app.Activity;",
- "import dagger.Component;",
- "import dagger.android.DispatchingAndroidInjector;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " DispatchingAndroidInjector<Activity> dispatchingInjector();",
- "}");
-
- Compilation compilation =
- javac()
- .withProcessors(ComponentProcessor.forTesting(new DuplicateAndroidInjectorsChecker()))
- .compile(activity, injectorFactory, module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Multiple injector factories bound for the same type")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- assertThat(compilation).hadErrorContaining("classKey(test.TestInjectorFactory)");
- assertThat(compilation).hadErrorContaining("stringKey(test.TestInjectorFactory)");
- assertThat(compilation).hadErrorCount(1);
- }
-}
diff --git a/javatests/dagger/android/support/AndroidSupportInjectionTest.java b/javatests/dagger/android/support/AndroidSupportInjectionTest.java
deleted file mode 100644
index 51e9992..0000000
--- a/javatests/dagger/android/support/AndroidSupportInjectionTest.java
+++ /dev/null
@@ -1,78 +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.android.support;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import android.app.Application;
-import android.support.v4.app.Fragment;
-import dagger.android.AndroidInjector;
-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
- public void injectFragment_simpleApplication() {
- Fragment fragment = new Fragment();
- SupportFragmentTestUtil.startFragment(fragment);
-
- try {
- AndroidSupportInjection.inject(fragment);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessageThat().contains("No injector was found");
- }
- }
-
- private static class ApplicationReturnsNull extends Application
- implements HasSupportFragmentInjector {
- @Override
- public AndroidInjector<Fragment> supportFragmentInjector() {
- return null;
- }
- }
-
- @Test
- @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
- public void fragmentInjector_returnsNull() {
- Fragment fragment = new Fragment();
- SupportFragmentTestUtil.startFragment(fragment);
-
- try {
- AndroidSupportInjection.inject(fragment);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessageThat().contains("supportFragmentInjector() returned null");
- }
- }
-
- @Test
- public void injectFragment_nullInput() {
- try {
- AndroidSupportInjection.inject(null);
- fail();
- } catch (NullPointerException e) {
- assertThat(e).hasMessageThat().contains("fragment");
- }
- }
-}
diff --git a/javatests/dagger/android/support/BUILD b/javatests/dagger/android/support/BUILD
deleted file mode 100644
index 6d8f43b..0000000
--- a/javatests/dagger/android/support/BUILD
+++ /dev/null
@@ -1,38 +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 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")
-
-GenRobolectricTests(
- name = "android-support-tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/android",
- "//java/dagger/android/support",
- "@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",
- ],
-)
diff --git a/javatests/dagger/android/support/functional/AllControllersAreDirectChildrenOfApplication.java b/javatests/dagger/android/support/functional/AllControllersAreDirectChildrenOfApplication.java
deleted file mode 100644
index fa05158..0000000
--- a/javatests/dagger/android/support/functional/AllControllersAreDirectChildrenOfApplication.java
+++ /dev/null
@@ -1,256 +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.android.support.functional;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.support.DaggerApplication;
-import dagger.android.support.functional.AllControllersAreDirectChildrenOfApplication.ApplicationComponent.BroadcastReceiverSubcomponent.BroadcastReceiverModule;
-import dagger.android.support.functional.AllControllersAreDirectChildrenOfApplication.ApplicationComponent.ContentProviderSubcomponent.ContentProviderModule;
-import dagger.android.support.functional.AllControllersAreDirectChildrenOfApplication.ApplicationComponent.InnerActivitySubcomponent.InnerActivityModule;
-import dagger.android.support.functional.AllControllersAreDirectChildrenOfApplication.ApplicationComponent.IntentServiceSubcomponent.IntentServiceModule;
-import dagger.android.support.functional.AllControllersAreDirectChildrenOfApplication.ApplicationComponent.ServiceSubcomponent.ServiceModule;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-
-public final class AllControllersAreDirectChildrenOfApplication extends DaggerApplication {
-
- @Override
- protected AndroidInjector<AllControllersAreDirectChildrenOfApplication> applicationInjector() {
- return DaggerAllControllersAreDirectChildrenOfApplication_ApplicationComponent.create();
- }
-
- @Component(modules = {ApplicationComponent.ApplicationModule.class, AndroidInjectionModule.class})
- interface ApplicationComponent
- extends AndroidInjector<AllControllersAreDirectChildrenOfApplication> {
- @Module(
- subcomponents = {
- ActivitySubcomponent.class,
- InnerActivitySubcomponent.class,
- ParentFragmentSubcomponent.class,
- ChildFragmentSubcomponent.class,
- DialogFragmentSubcomponent.class,
- ServiceSubcomponent.class,
- IntentServiceSubcomponent.class,
- BroadcastReceiverSubcomponent.class,
- ContentProviderSubcomponent.class
- }
- )
- abstract class ApplicationModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ApplicationComponent.class;
- }
-
- @Binds
- @IntoMap
- @ClassKey(TestActivity.class)
- abstract AndroidInjector.Factory<?> bindFactoryForTestActivity(
- ActivitySubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(OuterClass.TestInnerClassActivity.class)
- abstract AndroidInjector.Factory<?> bindFactoryForInnerActivity(
- InnerActivitySubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestParentFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForParentFragment(
- ParentFragmentSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestChildFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForChildFragment(
- ChildFragmentSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestDialogFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForDialogFragment(
- DialogFragmentSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestService.class)
- abstract AndroidInjector.Factory<?> bindFactoryForService(
- ServiceSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestIntentService.class)
- abstract AndroidInjector.Factory<?> bindFactoryForIntentService(
- IntentServiceSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestBroadcastReceiver.class)
- abstract AndroidInjector.Factory<?> bindFactoryForBroadcastReceiver(
- BroadcastReceiverSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestContentProvider.class)
- abstract AndroidInjector.Factory<?> bindFactoryForContentProvider(
- ContentProviderSubcomponent.Builder builder);
- }
-
- @Subcomponent(modules = ActivitySubcomponent.ActivityModule.class)
- interface ActivitySubcomponent extends AndroidInjector<TestActivity> {
- @Module
- abstract class ActivityModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ActivitySubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestActivity> {}
- }
-
- @Subcomponent(modules = InnerActivityModule.class)
- interface InnerActivitySubcomponent extends AndroidInjector<OuterClass.TestInnerClassActivity> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<OuterClass.TestInnerClassActivity> {}
-
- @Module
- abstract class InnerActivityModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return InnerActivitySubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = ParentFragmentSubcomponent.ParentFragmentModule.class)
- interface ParentFragmentSubcomponent extends AndroidInjector<TestParentFragment> {
- @Module
- abstract class ParentFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ParentFragmentSubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestParentFragment> {}
- }
-
- @Subcomponent(modules = ChildFragmentSubcomponent.ChildFragmentModule.class)
- interface ChildFragmentSubcomponent extends AndroidInjector<TestChildFragment> {
- @Module
- abstract class ChildFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ChildFragmentSubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestChildFragment> {}
- }
-
- @Subcomponent(modules = DialogFragmentSubcomponent.DialogFragmentModule.class)
- interface DialogFragmentSubcomponent extends AndroidInjector<TestDialogFragment> {
- @Module
- abstract class DialogFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return DialogFragmentSubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestDialogFragment> {}
- }
-
- @Subcomponent(modules = ServiceModule.class)
- interface ServiceSubcomponent extends AndroidInjector<TestService> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestService> {}
-
- @Module
- abstract class ServiceModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ServiceSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = IntentServiceModule.class)
- interface IntentServiceSubcomponent extends AndroidInjector<TestIntentService> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestIntentService> {}
-
- @Module
- abstract class IntentServiceModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return IntentServiceSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = BroadcastReceiverModule.class)
- interface BroadcastReceiverSubcomponent extends AndroidInjector<TestBroadcastReceiver> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestBroadcastReceiver> {}
-
- @Module
- abstract class BroadcastReceiverModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return BroadcastReceiverSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = ContentProviderModule.class)
- interface ContentProviderSubcomponent extends AndroidInjector<TestContentProvider> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestContentProvider> {}
-
- @Module
- abstract class ContentProviderModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ContentProviderSubcomponent.class;
- }
- }
- }
- }
-}
diff --git a/javatests/dagger/android/support/functional/AndroidManifest.xml b/javatests/dagger/android/support/functional/AndroidManifest.xml
deleted file mode 100644
index 2e40a35..0000000
--- a/javatests/dagger/android/support/functional/AndroidManifest.xml
+++ /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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.android.support.functional">
-
- <uses-sdk android:minSdkVersion="1" android:targetSdkVersion="26" />
-
- <application android:theme="@style/Theme.AppCompat"
- android:name=".UsesGeneratedModulesApplication">
- <activity android:name="dagger.android.support.functional.ParentOfFragmentActivity"/>
- <activity android:name="dagger.android.support.functional.SiblingOfFragmentActivity"/>
- <activity android:name="dagger.android.support.functional.InjectedWithoutSubcomponentActivity"/>
- </application>
-</manifest>
diff --git a/javatests/dagger/android/support/functional/BUILD b/javatests/dagger/android/support/functional/BUILD
deleted file mode 100644
index 130b971..0000000
--- a/javatests/dagger/android/support/functional/BUILD
+++ /dev/null
@@ -1,56 +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:
-# Functional test code for Dagger-Android
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "functional",
- srcs = glob(
- ["*.java"],
- exclude = ["*Test.java"],
- ),
- exports_manifest = 1,
- manifest = "AndroidManifest.xml",
- resource_files = glob(["res/**"]),
- deps = [
- "@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",
- # TODO(ronshapiro): figure out why strict deps is failing without this
- "@google_bazel_common//third_party/java/jsr250_annotations",
- ],
-)
-
-load("//:test_defs.bzl", "GenRobolectricTests")
-
-GenRobolectricTests(
- name = "functional_tests",
- srcs = glob(["*Test.java"]),
- deps = [
- ":functional",
- "//: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",
- ],
-)
diff --git a/javatests/dagger/android/support/functional/ComponentStructureFollowsControllerStructureApplication.java b/javatests/dagger/android/support/functional/ComponentStructureFollowsControllerStructureApplication.java
deleted file mode 100644
index 48e9a59..0000000
--- a/javatests/dagger/android/support/functional/ComponentStructureFollowsControllerStructureApplication.java
+++ /dev/null
@@ -1,255 +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.android.support.functional;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.support.DaggerApplication;
-import dagger.android.support.functional.ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.BroadcastReceiverSubcomponent.BroadcastReceiverModule;
-import dagger.android.support.functional.ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.ContentProviderSubcomponent.ContentProviderModule;
-import dagger.android.support.functional.ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.InnerActivitySubcomponent.InnerActivityModule;
-import dagger.android.support.functional.ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.IntentServiceSubcomponent.IntentServiceModule;
-import dagger.android.support.functional.ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.ServiceSubcomponent.ServiceModule;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-
-public final class ComponentStructureFollowsControllerStructureApplication
- extends DaggerApplication {
-
- @Override
- protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
- return DaggerComponentStructureFollowsControllerStructureApplication_ApplicationComponent
- .create();
- }
-
- @Component(modules = {ApplicationComponent.ApplicationModule.class, AndroidInjectionModule.class})
- interface ApplicationComponent
- extends AndroidInjector<ComponentStructureFollowsControllerStructureApplication> {
- @Module(
- subcomponents = {
- ActivitySubcomponent.class,
- InnerActivitySubcomponent.class,
- ServiceSubcomponent.class,
- IntentServiceSubcomponent.class,
- BroadcastReceiverSubcomponent.class,
- ContentProviderSubcomponent.class,
- }
- )
- abstract class ApplicationModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ApplicationComponent.class;
- }
-
- @Binds
- @IntoMap
- @ClassKey(TestActivity.class)
- abstract AndroidInjector.Factory<?> bindFactoryForTestActivity(
- ActivitySubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(OuterClass.TestInnerClassActivity.class)
- abstract AndroidInjector.Factory<?> bindFactoryForInnerActivity(
- InnerActivitySubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestService.class)
- abstract AndroidInjector.Factory<?> bindFactoryForService(
- ServiceSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestIntentService.class)
- abstract AndroidInjector.Factory<?> bindFactoryForIntentService(
- IntentServiceSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestBroadcastReceiver.class)
- abstract AndroidInjector.Factory<?> bindFactoryForBroadcastReceiver(
- BroadcastReceiverSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestContentProvider.class)
- abstract AndroidInjector.Factory<?> bindFactoryForContentProvider(
- ContentProviderSubcomponent.Builder builder);
- }
-
- @Subcomponent(modules = ActivitySubcomponent.ActivityModule.class)
- interface ActivitySubcomponent extends AndroidInjector<TestActivity> {
- @Module(subcomponents = {ParentFragmentSubcomponent.class, DialogFragmentSubcomponent.class})
- abstract class ActivityModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ActivitySubcomponent.class;
- }
-
- @Binds
- @IntoMap
- @ClassKey(TestParentFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForParentFragment(
- ParentFragmentSubcomponent.Builder builder);
-
- @Binds
- @IntoMap
- @ClassKey(TestDialogFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForDialogFragment(
- DialogFragmentSubcomponent.Builder builder);
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestActivity> {}
-
- @Subcomponent(modules = ParentFragmentSubcomponent.ParentFragmentModule.class)
- interface ParentFragmentSubcomponent extends AndroidInjector<TestParentFragment> {
- @Module(subcomponents = ChildFragmentSubcomponent.class)
- abstract class ParentFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ParentFragmentSubcomponent.class;
- }
-
- @Binds
- @IntoMap
- @ClassKey(TestChildFragment.class)
- abstract AndroidInjector.Factory<?> bindFactoryForChildFragment(
- ChildFragmentSubcomponent.Builder builder);
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestParentFragment> {}
-
- @Subcomponent(modules = ChildFragmentSubcomponent.ChildFragmentModule.class)
- interface ChildFragmentSubcomponent extends AndroidInjector<TestChildFragment> {
- @Module
- abstract class ChildFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ChildFragmentSubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestChildFragment> {}
- }
- }
-
- @Subcomponent(modules = DialogFragmentSubcomponent.DialogFragmentModule.class)
- interface DialogFragmentSubcomponent extends AndroidInjector<TestDialogFragment> {
- @Module
- abstract class DialogFragmentModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return DialogFragmentSubcomponent.class;
- }
- }
-
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestDialogFragment> {}
- }
- }
-
- @Subcomponent(modules = InnerActivityModule.class)
- interface InnerActivitySubcomponent extends AndroidInjector<OuterClass.TestInnerClassActivity> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<OuterClass.TestInnerClassActivity> {}
-
- @Module
- abstract class InnerActivityModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return InnerActivitySubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = ServiceModule.class)
- interface ServiceSubcomponent extends AndroidInjector<TestService> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestService> {}
-
- @Module
- abstract class ServiceModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ServiceSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = IntentServiceModule.class)
- interface IntentServiceSubcomponent extends AndroidInjector<TestIntentService> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestIntentService> {}
-
- @Module
- abstract class IntentServiceModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return IntentServiceSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = BroadcastReceiverModule.class)
- interface BroadcastReceiverSubcomponent extends AndroidInjector<TestBroadcastReceiver> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestBroadcastReceiver> {}
-
- @Module
- abstract class BroadcastReceiverModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return BroadcastReceiverSubcomponent.class;
- }
- }
- }
-
- @Subcomponent(modules = ContentProviderModule.class)
- interface ContentProviderSubcomponent extends AndroidInjector<TestContentProvider> {
- @Subcomponent.Builder
- abstract class Builder extends AndroidInjector.Builder<TestContentProvider> {}
-
- @Module
- abstract class ContentProviderModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ContentProviderSubcomponent.class;
- }
- }
- }
- }
-}
diff --git a/javatests/dagger/android/support/functional/InjectorsTest.java b/javatests/dagger/android/support/functional/InjectorsTest.java
deleted file mode 100644
index c5cb150..0000000
--- a/javatests/dagger/android/support/functional/InjectorsTest.java
+++ /dev/null
@@ -1,255 +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.android.support.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Intent;
-import android.content.res.Configuration;
-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;
-
-@RunWith(RobolectricTestRunner.class)
-public class InjectorsTest {
- private ActivityController<TestActivity> activityController;
- private TestActivity activity;
- private TestParentFragment parentFragment;
- private TestChildFragment childFragment;
- private TestDialogFragment dialogFragment;
- private TestService service;
- private TestIntentService intentService;
- private TestBroadcastReceiver broadcastReceiver;
- private TestContentProvider contentProvider;
-
- @Before
- public void setUp() {
- activityController = Robolectric.buildActivity(TestActivity.class);
- activity = activityController.setup().get();
- parentFragment =
- (TestParentFragment)
- activity.getSupportFragmentManager().findFragmentByTag("parent-fragment");
- childFragment =
- (TestChildFragment)
- parentFragment.getChildFragmentManager().findFragmentByTag("child-fragment");
- dialogFragment =
- (TestDialogFragment)
- activity.getSupportFragmentManager().findFragmentByTag("dialog-fragment");
-
- service = Robolectric.buildService(TestService.class).create().get();
- intentService = Robolectric.buildIntentService(TestIntentService.class).create().get();
-
- broadcastReceiver = new TestBroadcastReceiver();
- broadcastReceiver.onReceive(RuntimeEnvironment.application, new Intent());
-
- contentProvider = Robolectric.setupContentProvider(TestContentProvider.class);
- }
-
- @Test
- @Config(application = ComponentStructureFollowsControllerStructureApplication.class)
- public void componentStructureFollowsControllerStructure() {
- assertThat(activity.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.class);
- assertThat(parentFragment.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.ParentFragmentSubcomponent.class);
- assertThat(childFragment.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.ParentFragmentSubcomponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.ParentFragmentSubcomponent.ChildFragmentSubcomponent.class);
- assertThat(dialogFragment.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ActivitySubcomponent.DialogFragmentSubcomponent.class);
-
- assertThat(service.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ServiceSubcomponent.class);
- assertThat(intentService.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .IntentServiceSubcomponent.class);
-
- assertThat(broadcastReceiver.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .BroadcastReceiverSubcomponent.class);
-
- assertThat(contentProvider.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .ContentProviderSubcomponent.class);
-
- changeConfiguration();
-
- OuterClass.TestInnerClassActivity innerClassActivity =
- Robolectric.setupActivity(OuterClass.TestInnerClassActivity.class);
- assertThat(innerClassActivity.componentHierarchy)
- .containsExactly(
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent.class,
- ComponentStructureFollowsControllerStructureApplication.ApplicationComponent
- .InnerActivitySubcomponent.class);
- }
-
- @Test
- @Config(application = AllControllersAreDirectChildrenOfApplication.class)
- public void allControllersAreDirectChildrenOfApplication() {
- assertThat(activity.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.ActivitySubcomponent
- .class);
- assertThat(parentFragment.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .ParentFragmentSubcomponent.class);
- assertThat(childFragment.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .ChildFragmentSubcomponent.class);
- assertThat(dialogFragment.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .DialogFragmentSubcomponent.class);
-
- assertThat(service.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.ServiceSubcomponent
- .class);
- assertThat(intentService.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .IntentServiceSubcomponent.class);
-
- assertThat(broadcastReceiver.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .BroadcastReceiverSubcomponent.class);
-
- assertThat(contentProvider.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .ContentProviderSubcomponent.class);
-
- changeConfiguration();
-
- OuterClass.TestInnerClassActivity innerClassActivity =
- Robolectric.setupActivity(OuterClass.TestInnerClassActivity.class);
- assertThat(innerClassActivity.componentHierarchy)
- .containsExactly(
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent.class,
- AllControllersAreDirectChildrenOfApplication.ApplicationComponent
- .InnerActivitySubcomponent.class);
- }
-
- @Test
- @Config(application = UsesGeneratedModulesApplication.class)
- public void usesGeneratedModules() {
- assertThat(activity.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyActivitySubcomponent.class);
- assertThat(parentFragment.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyParentFragmentSubcomponent.class);
- assertThat(childFragment.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyChildFragmentSubcomponent.class);
- assertThat(dialogFragment.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyDialogFragmentSubcomponent.class);
-
- assertThat(service.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyServiceSubcomponent.class);
- assertThat(intentService.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyIntentServiceSubcomponent.class);
-
- assertThat(broadcastReceiver.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyBroadcastReceiverSubcomponent.class);
-
- assertThat(contentProvider.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyContentProviderSubcomponent.class);
-
- changeConfiguration();
-
- TestActivityWithScope activityWithScope =
- Robolectric.setupActivity(TestActivityWithScope.class);
- assertThat(activityWithScope.scopedStringProvider.get())
- .isSameInstanceAs(activityWithScope.scopedStringProvider.get());
-
- OuterClass.TestInnerClassActivity innerClassActivity =
- Robolectric.setupActivity(OuterClass.TestInnerClassActivity.class);
- assertThat(innerClassActivity.componentHierarchy)
- .containsExactly(
- UsesGeneratedModulesApplication.ApplicationComponent.class,
- UsesGeneratedModulesApplication.DummyInnerActivitySubcomponent.class);
- }
-
- // https://github.com/google/dagger/issues/598
- private void changeConfiguration() {
- Configuration oldConfiguration = activity.getResources().getConfiguration();
- Configuration newConfiguration = new Configuration(oldConfiguration);
- newConfiguration.orientation =
- oldConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE
- ? Configuration.ORIENTATION_PORTRAIT
- : Configuration.ORIENTATION_LANDSCAPE;
- activityController.configurationChange(newConfiguration);
- }
-}
diff --git a/javatests/dagger/android/support/functional/OuterClass.java b/javatests/dagger/android/support/functional/OuterClass.java
deleted file mode 100644
index e5d6ed5..0000000
--- a/javatests/dagger/android/support/functional/OuterClass.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.android.support.functional;
-
-import dagger.android.support.DaggerAppCompatActivity;
-import java.util.Set;
-import javax.inject.Inject;
-
-final class OuterClass {
- public static class TestInnerClassActivity extends DaggerAppCompatActivity {
- @Inject
- Set<Class<?>> componentHierarchy;
- }
-}
diff --git a/javatests/dagger/android/support/functional/TestActivity.java b/javatests/dagger/android/support/functional/TestActivity.java
deleted file mode 100644
index 84c44fd..0000000
--- a/javatests/dagger/android/support/functional/TestActivity.java
+++ /dev/null
@@ -1,39 +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.android.support.functional;
-
-import android.os.Bundle;
-import dagger.android.support.DaggerAppCompatActivity;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestActivity extends DaggerAppCompatActivity {
- @Inject Set<Class<?>> componentHierarchy;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_layout);
-
- getSupportFragmentManager()
- .beginTransaction()
- .add(new TestParentFragment(), "parent-fragment")
- .add(new TestDialogFragment(), "dialog-fragment")
- .commit();
- }
-}
diff --git a/javatests/dagger/android/support/functional/TestActivityWithScope.java b/javatests/dagger/android/support/functional/TestActivityWithScope.java
deleted file mode 100644
index d7cb891..0000000
--- a/javatests/dagger/android/support/functional/TestActivityWithScope.java
+++ /dev/null
@@ -1,25 +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.android.support.functional;
-
-import dagger.android.support.DaggerAppCompatActivity;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-public final class TestActivityWithScope extends DaggerAppCompatActivity {
- @Inject Provider<String> scopedStringProvider;
-}
diff --git a/javatests/dagger/android/support/functional/TestBroadcastReceiver.java b/javatests/dagger/android/support/functional/TestBroadcastReceiver.java
deleted file mode 100644
index edf93fe..0000000
--- a/javatests/dagger/android/support/functional/TestBroadcastReceiver.java
+++ /dev/null
@@ -1,25 +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.android.support.functional;
-
-import dagger.android.DaggerBroadcastReceiver;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestBroadcastReceiver extends DaggerBroadcastReceiver {
- @Inject Set<Class<?>> componentHierarchy;
-}
diff --git a/javatests/dagger/android/support/functional/TestChildFragment.java b/javatests/dagger/android/support/functional/TestChildFragment.java
deleted file mode 100644
index 781c578..0000000
--- a/javatests/dagger/android/support/functional/TestChildFragment.java
+++ /dev/null
@@ -1,25 +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.android.support.functional;
-
-import dagger.android.support.DaggerFragment;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestChildFragment extends DaggerFragment {
- @Inject Set<Class<?>> componentHierarchy;
-}
diff --git a/javatests/dagger/android/support/functional/TestContentProvider.java b/javatests/dagger/android/support/functional/TestContentProvider.java
deleted file mode 100644
index 1668ce6..0000000
--- a/javatests/dagger/android/support/functional/TestContentProvider.java
+++ /dev/null
@@ -1,59 +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.android.support.functional;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.Nullable;
-import dagger.android.DaggerContentProvider;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestContentProvider extends DaggerContentProvider {
- @Inject
- Set<Class<?>> componentHierarchy;
-
- @Nullable
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- throw new UnsupportedOperationException();
- }
-
- @Nullable
- @Override
- public String getType(Uri uri) {
- throw new UnsupportedOperationException();
- }
-
- @Nullable
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/javatests/dagger/android/support/functional/TestDialogFragment.java b/javatests/dagger/android/support/functional/TestDialogFragment.java
deleted file mode 100644
index d499ee5..0000000
--- a/javatests/dagger/android/support/functional/TestDialogFragment.java
+++ /dev/null
@@ -1,25 +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.android.support.functional;
-
-import dagger.android.support.DaggerAppCompatDialogFragment;
-import java.util.Set;
-import javax.inject.Inject;
-
-public class TestDialogFragment extends DaggerAppCompatDialogFragment {
- @Inject Set<Class<?>> componentHierarchy;
-}
diff --git a/javatests/dagger/android/support/functional/TestIntentService.java b/javatests/dagger/android/support/functional/TestIntentService.java
deleted file mode 100644
index 7f36e93..0000000
--- a/javatests/dagger/android/support/functional/TestIntentService.java
+++ /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.
- */
-
-package dagger.android.support.functional;
-
-import android.content.Intent;
-import dagger.android.DaggerIntentService;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestIntentService extends DaggerIntentService {
- @Inject Set<Class<?>> componentHierarchy;
-
- public TestIntentService() {
- super("TestIntentService");
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {}
-}
diff --git a/javatests/dagger/android/support/functional/TestParentFragment.java b/javatests/dagger/android/support/functional/TestParentFragment.java
deleted file mode 100644
index 6d2d6f4..0000000
--- a/javatests/dagger/android/support/functional/TestParentFragment.java
+++ /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.
- */
-
-package dagger.android.support.functional;
-
-import android.content.Context;
-import dagger.android.support.DaggerFragment;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestParentFragment extends DaggerFragment {
- @Inject Set<Class<?>> componentHierarchy;
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- getChildFragmentManager()
- .beginTransaction()
- .add(new TestChildFragment(), "child-fragment")
- .commit();
- }
-}
diff --git a/javatests/dagger/android/support/functional/TestService.java b/javatests/dagger/android/support/functional/TestService.java
deleted file mode 100644
index d3c6dc1..0000000
--- a/javatests/dagger/android/support/functional/TestService.java
+++ /dev/null
@@ -1,77 +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.android.support.functional;
-
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.RemoteException;
-import dagger.android.DaggerService;
-import java.io.FileDescriptor;
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class TestService extends DaggerService {
- @Inject Set<Class<?>> componentHierarchy;
-
- @Override
- public IBinder onBind(Intent intent) {
- return new MockBinder();
- }
-
- private static class MockBinder implements IBinder {
- @Override
- public String getInterfaceDescriptor() throws RemoteException {
- return null;
- }
-
- @Override
- public boolean pingBinder() {
- return false;
- }
-
- @Override
- public boolean isBinderAlive() {
- return false;
- }
-
- @Override
- public IInterface queryLocalInterface(String descriptor) {
- return null;
- }
-
- @Override
- public void dump(FileDescriptor fd, String[] args) throws RemoteException {}
-
- @Override
- public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {}
-
- @Override
- public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
- return false;
- }
-
- @Override
- public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {}
-
- @Override
- public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
- return false;
- }
- }
-}
diff --git a/javatests/dagger/android/support/functional/UsesGeneratedModulesApplication.java b/javatests/dagger/android/support/functional/UsesGeneratedModulesApplication.java
deleted file mode 100644
index 002da89..0000000
--- a/javatests/dagger/android/support/functional/UsesGeneratedModulesApplication.java
+++ /dev/null
@@ -1,194 +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.android.support.functional;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.ContributesAndroidInjector;
-import dagger.android.support.DaggerApplication;
-import dagger.multibindings.IntoSet;
-import java.lang.annotation.Retention;
-import java.util.UUID;
-import javax.inject.Scope;
-
-public final class UsesGeneratedModulesApplication extends DaggerApplication {
-
- @Override
- protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
- return DaggerUsesGeneratedModulesApplication_ApplicationComponent.create();
- }
-
- @Component(modules = {ApplicationModule.class, AndroidInjectionModule.class})
- interface ApplicationComponent extends AndroidInjector<UsesGeneratedModulesApplication> {}
-
- @Module
- abstract static class ApplicationModule {
- @Provides
- @IntoSet
- static Class<?> addToComponentHierarchy() {
- return ApplicationComponent.class;
- }
-
- @ActivityScope
- @ContributesAndroidInjector(modules = ActivityScopedModule.class)
- abstract TestActivityWithScope contributeTestActivityWithScopeInjector();
-
- @ContributesAndroidInjector(modules = DummyActivitySubcomponent.AddToHierarchy.class)
- abstract TestActivity contributeTestActivityInjector();
-
- @ContributesAndroidInjector(modules = DummyInnerActivitySubcomponent.AddToHierarchy.class)
- abstract OuterClass.TestInnerClassActivity contributeInnerActivityInjector();
-
- @ContributesAndroidInjector(modules = DummyParentFragmentSubcomponent.AddToHierarchy.class)
- abstract TestParentFragment contributeTestParentFragmentInjector();
-
- @ContributesAndroidInjector(modules = DummyChildFragmentSubcomponent.AddToHierarchy.class)
- abstract TestChildFragment contributeTestChildFragmentInjector();
-
- @ContributesAndroidInjector(modules = DummyDialogFragmentSubcomponent.AddToHierarchy.class)
- abstract TestDialogFragment contributeTestDialogFragmentInjector();
-
- @ContributesAndroidInjector(modules = DummyServiceSubcomponent.AddToHierarchy.class)
- abstract TestService contributeTestServiceInjector();
-
- @ContributesAndroidInjector(modules = DummyIntentServiceSubcomponent.AddToHierarchy.class)
- abstract TestIntentService contributeTestIntentServiceInjector();
-
- @ContributesAndroidInjector(modules = DummyBroadcastReceiverSubcomponent.AddToHierarchy.class)
- abstract TestBroadcastReceiver contributeTestBroadcastReceiverInjector();
-
- @ContributesAndroidInjector(modules = DummyContentProviderSubcomponent.AddToHierarchy.class)
- abstract TestContentProvider contributeTestContentProviderInjector();
- }
-
- @Retention(RUNTIME)
- @Scope
- @interface ActivityScope {}
-
- @Module
- static class ActivityScopedModule {
- @Provides
- @ActivityScope
- static String provideScopedString() {
- return UUID.randomUUID().toString();
- }
- }
-
- interface DummyActivitySubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyActivitySubcomponent.class;
- }
- }
- }
-
- interface DummyInnerActivitySubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyInnerActivitySubcomponent.class;
- }
- }
- }
-
- interface DummyParentFragmentSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyParentFragmentSubcomponent.class;
- }
- }
- }
-
- interface DummyChildFragmentSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyChildFragmentSubcomponent.class;
- }
- }
- }
-
- interface DummyDialogFragmentSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyDialogFragmentSubcomponent.class;
- }
- }
- }
-
- interface DummyServiceSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyServiceSubcomponent.class;
- }
- }
- }
-
- interface DummyIntentServiceSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyIntentServiceSubcomponent.class;
- }
- }
- }
-
- interface DummyBroadcastReceiverSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyBroadcastReceiverSubcomponent.class;
- }
- }
- }
-
- interface DummyContentProviderSubcomponent {
- @Module
- abstract class AddToHierarchy {
- @Provides
- @IntoSet
- static Class<?> addDummyValueToComponentHierarchy() {
- return DummyContentProviderSubcomponent.class;
- }
- }
- }
-}
diff --git a/javatests/dagger/android/support/functional/res/layout/activity_layout.xml b/javatests/dagger/android/support/functional/res/layout/activity_layout.xml
deleted file mode 100644
index d886d97..0000000
--- a/javatests/dagger/android/support/functional/res/layout/activity_layout.xml
+++ /dev/null
@@ -1,21 +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.
- -->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/fragment_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
diff --git a/javatests/dagger/functional/A.java b/javatests/dagger/functional/A.java
deleted file mode 100644
index c295dc1..0000000
--- a/javatests/dagger/functional/A.java
+++ /dev/null
@@ -1,23 +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.functional;
-
-import javax.inject.Inject;
-
-class A {
- @Inject A() {}
-}
diff --git a/javatests/dagger/functional/AbstractMembersInjectingBaseClass.java b/javatests/dagger/functional/AbstractMembersInjectingBaseClass.java
deleted file mode 100644
index fcab318..0000000
--- a/javatests/dagger/functional/AbstractMembersInjectingBaseClass.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import javax.inject.Inject;
-
-abstract class AbstractMembersInjectingBaseClass {
- @Inject Thing thing;
-}
-
diff --git a/javatests/dagger/functional/AbstractMiddleClassWithoutMembers.java b/javatests/dagger/functional/AbstractMiddleClassWithoutMembers.java
deleted file mode 100644
index 4ff55eb..0000000
--- a/javatests/dagger/functional/AbstractMiddleClassWithoutMembers.java
+++ /dev/null
@@ -1,21 +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.functional;
-
-abstract class AbstractMiddleClassWithoutMembers extends AbstractMembersInjectingBaseClass {
-}
-
diff --git a/javatests/dagger/functional/B.java b/javatests/dagger/functional/B.java
deleted file mode 100644
index 55d05af..0000000
--- a/javatests/dagger/functional/B.java
+++ /dev/null
@@ -1,23 +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.functional;
-
-import javax.inject.Inject;
-
-class B {
- @Inject B() {}
-}
diff --git a/javatests/dagger/functional/BUILD b/javatests/dagger/functional/BUILD
deleted file mode 100644
index f417bec..0000000
--- a/javatests/dagger/functional/BUILD
+++ /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.
-
-# Description:
-# Functional tests for Dagger
-
-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(
- ["**/*.java"],
- ),
- 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 = [
- "@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",
- ],
- 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/BasicAbstractClassComponent.java b/javatests/dagger/functional/BasicAbstractClassComponent.java
deleted file mode 100644
index 2bd849d..0000000
--- a/javatests/dagger/functional/BasicAbstractClassComponent.java
+++ /dev/null
@@ -1,30 +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.functional;
-
-import dagger.Component;
-
-/**
- * This component tests behavior equivalent to {@link BasicComponent}, but as an abstract class
- * rather than an interface.
- */
-@Component(modules = {PrimitivesModule.class, NullableModule.class})
-abstract class BasicAbstractClassComponent implements BasicComponent {
- void throwAParty() {
- throw new RuntimeException("Paaarrrrrtaaaaaaaay!");
- }
-}
diff --git a/javatests/dagger/functional/BasicComponent.java b/javatests/dagger/functional/BasicComponent.java
deleted file mode 100644
index 295c1e1..0000000
--- a/javatests/dagger/functional/BasicComponent.java
+++ /dev/null
@@ -1,93 +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.functional;
-
-import dagger.Component;
-import dagger.Lazy;
-import dagger.MembersInjector;
-import dagger.functional.NullableModule.Nullable;
-import javax.inject.Provider;
-
-@Component(modules = {PrimitivesModule.class, NullableModule.class})
-interface BasicComponent
- extends Injector<Thing>,
- // Implements two types that define the same method, not overridden here, to test that the
- // method is implemented only once.
- ComponentSupertypeOne,
- ComponentSupertypeTwo {
- byte getByte();
- char getChar();
- short getShort();
- int getInt();
- long getLong();
- boolean getBoolean();
- float getFloat();
- double getDouble();
-
- Byte getBoxedByte();
- Character getBoxedChar();
- Short getBoxedShort();
- Integer getBoxedInt();
- Long getBoxedLong();
- Boolean getBoxedBoolean();
- Float getBoxedFloat();
- Double getBoxedDouble();
-
- Provider<Byte> getByteProvider();
- Provider<Character> getCharProvider();
- Provider<Short> getShortProvider();
- Provider<Integer> getIntProvider();
- Provider<Long> getLongProvider();
- Provider<Boolean> getBooleanProvider();
- Provider<Float> getFloatProvider();
- Provider<Double> getDoubleProvider();
-
- byte[] getByteArray();
- char[] getCharArray();
- short[] getShortArray();
- int[] getIntArray();
- long[] getLongArray();
- boolean[] getBooleanArray();
- float[] getFloatArray();
- double[] getDoubleArray();
-
- Provider<byte[]> getByteArrayProvider();
- Provider<char[]> getCharArrayProvider();
- Provider<short[]> getShortArrayProvider();
- Provider<int[]> getIntArrayProvider();
- Provider<long[]> getLongArrayProvider();
- Provider<boolean[]> getBooleanArrayProvider();
- Provider<float[]> getFloatArrayProvider();
- Provider<double[]> getDoubleArrayProvider();
-
- Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject);
-
- Thing thing();
- InjectedThing injectedThing();
- Provider<InjectedThing> injectedThingProvider();
- Lazy<InjectedThing> lazyInjectedThing();
- Provider<Lazy<InjectedThing>> lazyInjectedThingProvider();
- MembersInjector<InjectedThing> injectedThingMembersInjector();
-
- @Nullable Object nullObject();
- Provider<Object> nullObjectProvider();
- Lazy<Object> lazyNullObject();
-
- TypeWithInheritedMembersInjection typeWithInheritedMembersInjection();
- MembersInjector<TypeWithInheritedMembersInjection>
- typeWithInheritedMembersInjectionMembersInjector();
-}
diff --git a/javatests/dagger/functional/BasicTest.java b/javatests/dagger/functional/BasicTest.java
deleted file mode 100644
index 80fc5e6..0000000
--- a/javatests/dagger/functional/BasicTest.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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.functional.PrimitivesModule.BOUND_BOOLEAN;
-import static dagger.functional.PrimitivesModule.BOUND_BOOLEAN_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_BYTE;
-import static dagger.functional.PrimitivesModule.BOUND_BYTE_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_CHAR;
-import static dagger.functional.PrimitivesModule.BOUND_CHAR_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_DOUBLE;
-import static dagger.functional.PrimitivesModule.BOUND_DOUBLE_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_FLOAT;
-import static dagger.functional.PrimitivesModule.BOUND_FLOAT_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_INT;
-import static dagger.functional.PrimitivesModule.BOUND_INT_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_LONG;
-import static dagger.functional.PrimitivesModule.BOUND_LONG_ARRAY;
-import static dagger.functional.PrimitivesModule.BOUND_SHORT;
-import static dagger.functional.PrimitivesModule.BOUND_SHORT_ARRAY;
-
-import dagger.Lazy;
-import javax.inject.Provider;
-import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class BasicTest {
- @DataPoint
- public static final BasicComponent basicComponent = DaggerBasicComponent.create();
- @DataPoint
- public static final BasicComponent abstractClassBasicComponent =
- DaggerBasicAbstractClassComponent.create();
-
- @Theory public void primitives(BasicComponent basicComponent) {
- assertThat(basicComponent.getByte()).isEqualTo(BOUND_BYTE);
- assertThat(basicComponent.getChar()).isEqualTo(BOUND_CHAR);
- assertThat(basicComponent.getShort()).isEqualTo(BOUND_SHORT);
- assertThat(basicComponent.getInt()).isEqualTo(BOUND_INT);
- assertThat(basicComponent.getLong()).isEqualTo(BOUND_LONG);
- assertThat(basicComponent.getBoolean()).isEqualTo(BOUND_BOOLEAN);
- assertThat(basicComponent.getFloat()).isEqualTo(BOUND_FLOAT);
- assertThat(basicComponent.getDouble()).isEqualTo(BOUND_DOUBLE);
- }
-
- @Theory public void boxedPrimitives(BasicComponent basicComponent) {
- assertThat(basicComponent.getBoxedByte()).isEqualTo(new Byte(BOUND_BYTE));
- assertThat(basicComponent.getBoxedChar()).isEqualTo(new Character(BOUND_CHAR));
- assertThat(basicComponent.getBoxedShort()).isEqualTo(new Short(BOUND_SHORT));
- assertThat(basicComponent.getBoxedInt()).isEqualTo(new Integer(BOUND_INT));
- assertThat(basicComponent.getBoxedLong()).isEqualTo(new Long(BOUND_LONG));
- assertThat(basicComponent.getBoxedBoolean()).isEqualTo(new Boolean(BOUND_BOOLEAN));
- assertThat(basicComponent.getBoxedFloat()).isEqualTo(BOUND_FLOAT);
- assertThat(basicComponent.getBoxedDouble()).isEqualTo(BOUND_DOUBLE);
- }
-
- @Theory public void boxedPrimitiveProviders(BasicComponent basicComponent) {
- assertThat(basicComponent.getByteProvider().get()).isEqualTo(new Byte(BOUND_BYTE));
- assertThat(basicComponent.getCharProvider().get()).isEqualTo(new Character(BOUND_CHAR));
- assertThat(basicComponent.getShortProvider().get()).isEqualTo(new Short(BOUND_SHORT));
- assertThat(basicComponent.getIntProvider().get()).isEqualTo(new Integer(BOUND_INT));
- assertThat(basicComponent.getLongProvider().get()).isEqualTo(new Long(BOUND_LONG));
- assertThat(basicComponent.getBooleanProvider().get()).isEqualTo(new Boolean(BOUND_BOOLEAN));
- assertThat(basicComponent.getFloatProvider().get()).isEqualTo(BOUND_FLOAT);
- assertThat(basicComponent.getDoubleProvider().get()).isEqualTo(BOUND_DOUBLE);
- }
-
- @Theory public void primitiveArrays(BasicComponent basicComponent) {
- assertThat(basicComponent.getByteArray()).isSameInstanceAs(BOUND_BYTE_ARRAY);
- assertThat(basicComponent.getCharArray()).isSameInstanceAs(BOUND_CHAR_ARRAY);
- assertThat(basicComponent.getShortArray()).isSameInstanceAs(BOUND_SHORT_ARRAY);
- assertThat(basicComponent.getIntArray()).isSameInstanceAs(BOUND_INT_ARRAY);
- assertThat(basicComponent.getLongArray()).isSameInstanceAs(BOUND_LONG_ARRAY);
- assertThat(basicComponent.getBooleanArray()).isSameInstanceAs(BOUND_BOOLEAN_ARRAY);
- assertThat(basicComponent.getFloatArray()).isSameInstanceAs(BOUND_FLOAT_ARRAY);
- assertThat(basicComponent.getDoubleArray()).isSameInstanceAs(BOUND_DOUBLE_ARRAY);
- }
-
- @Theory public void primitiveArrayProviders(BasicComponent basicComponent) {
- assertThat(basicComponent.getByteArrayProvider().get()).isSameInstanceAs(BOUND_BYTE_ARRAY);
- assertThat(basicComponent.getCharArrayProvider().get()).isSameInstanceAs(BOUND_CHAR_ARRAY);
- assertThat(basicComponent.getShortArrayProvider().get()).isSameInstanceAs(BOUND_SHORT_ARRAY);
- assertThat(basicComponent.getIntArrayProvider().get()).isSameInstanceAs(BOUND_INT_ARRAY);
- assertThat(basicComponent.getLongArrayProvider().get()).isSameInstanceAs(BOUND_LONG_ARRAY);
- assertThat(basicComponent.getBooleanArrayProvider().get())
- .isSameInstanceAs(BOUND_BOOLEAN_ARRAY);
- assertThat(basicComponent.getFloatArrayProvider().get()).isSameInstanceAs(BOUND_FLOAT_ARRAY);
- assertThat(basicComponent.getDoubleArrayProvider().get()).isSameInstanceAs(BOUND_DOUBLE_ARRAY);
- }
-
- @Theory public void noOpMembersInjection(BasicComponent basicComponent) {
- Object object = new Object();
- assertThat(basicComponent.noOpMembersInjection(object)).isSameInstanceAs(object);
- }
-
- @Theory public void basicObject_noDeps(BasicComponent basicComponent) {
- assertThat(basicComponent.thing()).isNotNull();
- }
-
- @Theory public void inheritedMembersInjection(BasicComponent basicComponent) {
- assertThat(basicComponent.typeWithInheritedMembersInjection().thing).isNotNull();
- }
-
- @Theory
- public void nullableInjection(BasicComponent basicComponent) {
- assertThat(basicComponent.nullObject()).isNull();
- assertThat(basicComponent.nullObjectProvider().get()).isNull();
- assertThat(basicComponent.lazyNullObject().get()).isNull();
- }
-
- @Theory
- public void providerOfLazy(BasicComponent basicComponent) {
- Provider<Lazy<InjectedThing>> lazyInjectedThingProvider =
- basicComponent.lazyInjectedThingProvider();
- Lazy<InjectedThing> lazyInjectedThing1 = lazyInjectedThingProvider.get();
- Lazy<InjectedThing> lazyInjectedThing2 = lazyInjectedThingProvider.get();
- assertThat(lazyInjectedThing2).isNotSameInstanceAs(lazyInjectedThing1);
- assertThat(lazyInjectedThing1.get()).isSameInstanceAs(lazyInjectedThing1.get());
- assertThat(lazyInjectedThing2.get()).isSameInstanceAs(lazyInjectedThing2.get());
- assertThat(lazyInjectedThing2.get()).isNotSameInstanceAs(lazyInjectedThing1.get());
- }
-}
diff --git a/javatests/dagger/functional/BooleanKey.java b/javatests/dagger/functional/BooleanKey.java
deleted file mode 100644
index 28e1c08..0000000
--- a/javatests/dagger/functional/BooleanKey.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.MapKey;
-
-@MapKey(unwrapValue = true)
-@interface BooleanKey {
- boolean value();
-}
diff --git a/javatests/dagger/functional/BoundedGenericComponent.java b/javatests/dagger/functional/BoundedGenericComponent.java
deleted file mode 100644
index 270316e..0000000
--- a/javatests/dagger/functional/BoundedGenericComponent.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.functional;
-
-import dagger.Component;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-@Component(modules = BoundedGenericModule.class)
-interface BoundedGenericComponent {
- BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
- bounds1();
- BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
- bounds2();
-}
diff --git a/javatests/dagger/functional/BoundedGenericModule.java b/javatests/dagger/functional/BoundedGenericModule.java
deleted file mode 100644
index b630cd6..0000000
--- a/javatests/dagger/functional/BoundedGenericModule.java
+++ /dev/null
@@ -1,82 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-@Module
-class BoundedGenericModule {
-
- @Provides
- Integer provideInteger() {
- return 1;
- }
-
- @Provides
- Double provideDouble() {
- return 2d;
- }
-
- @Provides
- ArrayList<String> provideArrayListString() {
- ArrayList<String> list = new ArrayList<>();
- list.add("arrayListOfString");
- return list;
- }
-
- @Provides
- LinkedList<String> provideLinkedListString() {
- LinkedList<String> list = new LinkedList<>();
- list.add("linkedListOfString");
- return list;
- }
-
- @Provides
- LinkedList<CharSequence> provideLinkedListCharSeq() {
- LinkedList<CharSequence> list = new LinkedList<>();
- list.add("linkedListOfCharSeq");
- return list;
- }
-
- @Provides
- @SuppressWarnings("unchecked")
- LinkedList<Comparable<String>> provideArrayListOfComparableString() {
- LinkedList<Comparable<String>> list = new LinkedList<>();
- list.add("arrayListOfComparableOfString");
- return list;
- }
-
- @Provides
- List<Integer> provideListOfInteger() {
- LinkedList<Integer> list = new LinkedList<>();
- list.add(3);
- return list;
- }
-
- @Provides
- Set<Double> provideSetOfDouble() {
- Set<Double> set = new HashSet<>();
- set.add(4d);
- return set;
- }
-}
diff --git a/javatests/dagger/functional/BoundedGenerics.java b/javatests/dagger/functional/BoundedGenerics.java
deleted file mode 100644
index 812cd04..0000000
--- a/javatests/dagger/functional/BoundedGenerics.java
+++ /dev/null
@@ -1,42 +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.functional;
-
-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>,
- D extends A,
- E extends Iterable<D>> {
-
- final A a;
- final B b;
- final C c;
- final D d;
- final E e;
-
- @Inject BoundedGenerics(A a, B b, C c, D d, E e) {
- this.a = a;
- this.b = b;
- this.c = c;
- this.d = d;
- this.e = e;
- }
-
-}
diff --git a/javatests/dagger/functional/BoxedPrimitives.java b/javatests/dagger/functional/BoxedPrimitives.java
deleted file mode 100644
index adb61f2..0000000
--- a/javatests/dagger/functional/BoxedPrimitives.java
+++ /dev/null
@@ -1,47 +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.functional;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import javax.inject.Provider;
-
-interface BoxedPrimitives {
- interface Dependency {
- int primitive();
- }
-
- @Component(dependencies = Dependency.class)
- interface ConsumesPrimitiveThroughDependency {
- Provider<Integer> providerOfBoxedPrimitive();
- }
-
- @Module
- class PrimitiveModule {
- @Provides
- static int providePrimitive() {
- return 1;
- }
- }
-
- @Component(modules = PrimitiveModule.class)
- interface ConsumesPrimitiveFromProvidesMethod {
- Provider<Integer> providerOfBoxedPrimitive();
- }
-
-}
diff --git a/javatests/dagger/functional/ByteKey.java b/javatests/dagger/functional/ByteKey.java
deleted file mode 100644
index f0ee7ec..0000000
--- a/javatests/dagger/functional/ByteKey.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.MapKey;
-
-@MapKey(unwrapValue = true)
-@interface ByteKey {
- byte value();
-}
diff --git a/javatests/dagger/functional/CharKey.java b/javatests/dagger/functional/CharKey.java
deleted file mode 100644
index 3e12785..0000000
--- a/javatests/dagger/functional/CharKey.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.MapKey;
-
-@MapKey(unwrapValue = true)
-@interface CharKey {
- char value();
-}
diff --git a/javatests/dagger/functional/ChildDoubleModule.java b/javatests/dagger/functional/ChildDoubleModule.java
deleted file mode 100644
index cff8f0b..0000000
--- a/javatests/dagger/functional/ChildDoubleModule.java
+++ /dev/null
@@ -1,37 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.ArrayList;
-import java.util.List;
-
-@Module
-class ChildDoubleModule extends ParentModule<Double, String, List<Double>> {
-
- @Provides Double provideDouble() {
- return 3d;
- }
-
- @Provides List<Double> provideListOfDouble() {
- List<Double> list = new ArrayList<>();
- list.add(4d);
- return list;
- }
-
-}
diff --git a/javatests/dagger/functional/ChildIntegerModule.java b/javatests/dagger/functional/ChildIntegerModule.java
deleted file mode 100644
index 45c7c1a..0000000
--- a/javatests/dagger/functional/ChildIntegerModule.java
+++ /dev/null
@@ -1,37 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.ArrayList;
-import java.util.List;
-
-@Module
-class ChildIntegerModule extends ParentModule<Integer, String, List<Integer>> {
-
- @Provides Integer provideInteger() {
- return 1;
- }
-
- @Provides List<Integer> provideListOfInteger() {
- List<Integer> list = new ArrayList<>();
- list.add(2);
- return list;
- }
-
-}
diff --git a/javatests/dagger/functional/ComplexGenerics.java b/javatests/dagger/functional/ComplexGenerics.java
deleted file mode 100644
index 9309583..0000000
--- a/javatests/dagger/functional/ComplexGenerics.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.functional;
-
-import dagger.Lazy;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-class ComplexGenerics {
-
- final Generic2<Generic<A>> g2ga;
- final Lazy<Generic2<Generic<A>>> g2gaLazy;
- final Provider<Generic2<Generic<A>>> g2gaProvider;
- final Generic2<Generic<B>> g2gb;
- final Lazy<Generic2<Generic<B>>> g2gbLazy;
- final Provider<Generic2<Generic<B>>> g2gbProvider;
- final Generic2<A> g2a;
- final Generic<Generic2<A>> gg2a;
- final Generic<Generic2<B>> gg2b;
-
- @Inject ComplexGenerics(
- Generic2<Generic<A>> g2ga,
- Lazy<Generic2<Generic<A>>> g2gaLazy,
- Provider<Generic2<Generic<A>>> g2gaProvider,
- Generic2<Generic<B>> g2gb,
- Lazy<Generic2<Generic<B>>> g2gbLazy,
- Provider<Generic2<Generic<B>>> g2gbProvider,
- Generic2<A> g2a,
- Generic<Generic2<A>> gg2a,
- Generic<Generic2<B>> gg2b) {
- this.g2ga = g2ga;
- this.g2gaLazy = g2gaLazy;
- this.g2gaProvider = g2gaProvider;
- this.g2gb = g2gb;
- this.g2gbLazy = g2gbLazy;
- this.g2gbProvider = g2gbProvider;
- this.g2a = g2a;
- this.gg2a = gg2a;
- this.gg2b = gg2b;
- }
-}
diff --git a/javatests/dagger/functional/ComponentDependsOnGeneratedCode.java b/javatests/dagger/functional/ComponentDependsOnGeneratedCode.java
deleted file mode 100644
index 9c44c5c..0000000
--- a/javatests/dagger/functional/ComponentDependsOnGeneratedCode.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.functional;
-
-import dagger.Component;
-
-/**
- * A component that indirectly depends on code generated by another processor, in this case
- * {@link com.google.auto.factory.AutoFactory}. Neither this type nor its immediately referenced
- * types are generated, but {@link NeedsFactory} depends on the generated
- * {@link NeedsFactory_SomethingFactory}.
- *
- */
-@Component
-interface ComponentDependsOnGeneratedCode {
- NeedsFactory needsFactory();
-}
diff --git a/javatests/dagger/functional/ComponentMethodTest.java b/javatests/dagger/functional/ComponentMethodTest.java
deleted file mode 100644
index 5e53ea4..0000000
--- a/javatests/dagger/functional/ComponentMethodTest.java
+++ /dev/null
@@ -1,82 +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.functional;
-
-import dagger.Component;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * This is a regression test that makes sure component method order does not affect initialization
- * order.
- */
-@RunWith(JUnit4.class)
-public final class ComponentMethodTest {
-
- static final class Dep1 {
-
- @Inject
- Dep1(Dep2 dep2) {}
- }
-
- static final class Dep2 {
-
- @Inject
- Dep2(Dep3 dep3) {}
- }
-
- static final class Dep3 {
-
- @Inject
- Dep3() {}
- }
-
- @Component
- interface NonTopologicalOrderComponent {
-
- Provider<Dep1> dep1Provider();
-
- Provider<Dep2> dep2Provider();
- }
-
- @Component
- interface TopologicalOrderComponent {
-
- Provider<Dep2> dep2Provider();
-
- Provider<Dep1> dep1Provider();
- }
-
- @Test
- public void testNonTopologicalOrderComponent() throws Exception {
- NonTopologicalOrderComponent component =
- DaggerComponentMethodTest_NonTopologicalOrderComponent.create();
- component.dep1Provider().get();
- component.dep2Provider().get();
- }
-
- @Test
- public void testTopologicalOrderComponent() throws Exception {
- TopologicalOrderComponent component =
- DaggerComponentMethodTest_TopologicalOrderComponent.create();
- component.dep1Provider().get();
- component.dep2Provider().get();
- }
-}
diff --git a/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCode.java b/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCode.java
deleted file mode 100644
index a26292a..0000000
--- a/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCode.java
+++ /dev/null
@@ -1,28 +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.functional;
-
-import dagger.Component;
-
-/**
- * A component whose supertype depends on code generated by another processor, in this case
- * {@link com.google.auto.factory.AutoFactory}.
- *
- */
-@Component
-interface ComponentSupertypeDependsOnGeneratedCode
- extends ComponentSupertypeDependsOnGeneratedCodeInterface {}
diff --git a/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCodeInterface.java b/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCodeInterface.java
deleted file mode 100644
index 7744d19..0000000
--- a/javatests/dagger/functional/ComponentSupertypeDependsOnGeneratedCodeInterface.java
+++ /dev/null
@@ -1,21 +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.functional;
-
-interface ComponentSupertypeDependsOnGeneratedCodeInterface {
- NeedsFactory_SomethingFactory somethingFactory();
-}
diff --git a/javatests/dagger/functional/ComponentSupertypeOne.java b/javatests/dagger/functional/ComponentSupertypeOne.java
deleted file mode 100644
index c63d1da..0000000
--- a/javatests/dagger/functional/ComponentSupertypeOne.java
+++ /dev/null
@@ -1,21 +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.functional;
-
-public interface ComponentSupertypeOne {
- Thing inheritedThing();
-}
diff --git a/javatests/dagger/functional/ComponentSupertypeTwo.java b/javatests/dagger/functional/ComponentSupertypeTwo.java
deleted file mode 100644
index 3c8312b..0000000
--- a/javatests/dagger/functional/ComponentSupertypeTwo.java
+++ /dev/null
@@ -1,21 +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.functional;
-
-public interface ComponentSupertypeTwo {
- Thing inheritedThing();
-}
diff --git a/javatests/dagger/functional/ComponentWithReusableBindings.java b/javatests/dagger/functional/ComponentWithReusableBindings.java
deleted file mode 100644
index afad0d7..0000000
--- a/javatests/dagger/functional/ComponentWithReusableBindings.java
+++ /dev/null
@@ -1,102 +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.functional;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Reusable;
-import dagger.Subcomponent;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-@Component(modules = ComponentWithReusableBindings.ReusableBindingsModule.class)
-interface ComponentWithReusableBindings {
-
- @Qualifier
- @interface InParent {}
-
- @Qualifier
- @interface InChildren {}
-
- @InParent
- Object reusableInParent();
-
- ChildOne childOne();
-
- ChildTwo childTwo();
-
- // b/77150738
- int primitive();
-
- // b/77150738: This is used as a regression test for fastInit mode's switching providers. In
- // particular, it occurs when a @Provides method returns the boxed type but the component method
- // returns the unboxed type, and the instance is requested from a SwitchingProvider.
- boolean unboxedPrimitive();
-
- // b/77150738
- Provider<Boolean> booleanProvider();
-
- @Subcomponent
- interface ChildOne {
- @InParent
- Object reusableInParent();
-
- @InChildren
- Object reusableInChild();
- }
-
- @Subcomponent
- interface ChildTwo {
- @InParent
- Object reusableInParent();
-
- @InChildren
- Object reusableInChild();
- }
-
- @Module
- static class ReusableBindingsModule {
- @Provides
- @Reusable
- @InParent
- static Object inParent() {
- return new Object();
- }
-
- @Provides
- @Reusable
- @InChildren
- static Object inChildren() {
- return new Object();
- }
-
- // b/77150738
- @Provides
- @Reusable
- static int primitive() {
- return 0;
- }
-
- // b/77150738
- @Provides
- @Reusable
- static Boolean boxedPrimitive() {
- return false;
- }
- }
-}
diff --git a/javatests/dagger/functional/ComponentsWithNestedModules.java b/javatests/dagger/functional/ComponentsWithNestedModules.java
deleted file mode 100644
index a42dd73..0000000
--- a/javatests/dagger/functional/ComponentsWithNestedModules.java
+++ /dev/null
@@ -1,34 +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.functional;
-
-import dagger.Component;
-import dagger.Module;
-
-// https://github.com/google/dagger/issues/279
-public class ComponentsWithNestedModules {
- @Component(modules = RegularComponent.SharedModule.class)
- public interface RegularComponent {
- @Module class SharedModule {}
- }
-
- @Component(modules = ExtendsRegularComponent.SharedModule.class)
- public interface ExtendsRegularComponent extends RegularComponent {
- @Module(includes = RegularComponent.SharedModule.class)
- class SharedModule {}
- }
-}
diff --git a/javatests/dagger/functional/DependsOnGeneratedCodeTest.java b/javatests/dagger/functional/DependsOnGeneratedCodeTest.java
deleted file mode 100644
index ca7631f..0000000
--- a/javatests/dagger/functional/DependsOnGeneratedCodeTest.java
+++ /dev/null
@@ -1,33 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * @see <a href="http://b/19435358">Bug 19435358</a>
- */
-@RunWith(JUnit4.class)
-public class DependsOnGeneratedCodeTest {
- @Test public void testComponentDependsOnGeneratedCode() {
- assertThat(DaggerComponentDependsOnGeneratedCode.create().needsFactory()).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/Generic.java b/javatests/dagger/functional/Generic.java
deleted file mode 100644
index 9e77efe..0000000
--- a/javatests/dagger/functional/Generic.java
+++ /dev/null
@@ -1,27 +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.functional;
-
-import javax.inject.Inject;
-
-public class Generic<T> {
- final T t;
-
- @Inject public Generic(T t) {
- this.t = t;
- }
-}
diff --git a/javatests/dagger/functional/Generic2.java b/javatests/dagger/functional/Generic2.java
deleted file mode 100644
index f53c0f8..0000000
--- a/javatests/dagger/functional/Generic2.java
+++ /dev/null
@@ -1,27 +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.functional;
-
-import javax.inject.Inject;
-
-public class Generic2<T> {
- final T t;
-
- @Inject Generic2(T t) {
- this.t = t;
- }
-}
diff --git a/javatests/dagger/functional/GenericChild.java b/javatests/dagger/functional/GenericChild.java
deleted file mode 100644
index bb7330e..0000000
--- a/javatests/dagger/functional/GenericChild.java
+++ /dev/null
@@ -1,34 +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.functional;
-
-import javax.inject.Inject;
-
-class GenericChild<T> extends GenericParent<T, B> {
-
- A registeredA;
- T registeredT;
-
- @Inject GenericChild() {}
-
- @Inject A a;
- @Inject T t;
-
- @Inject void registerA(A a) { this.registeredA = a; }
- @Inject void registerT(T t) { this.registeredT = t; }
-
-}
diff --git a/javatests/dagger/functional/GenericComponent.java b/javatests/dagger/functional/GenericComponent.java
deleted file mode 100644
index e27df3b..0000000
--- a/javatests/dagger/functional/GenericComponent.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.functional;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.functional.GenericComponent.NongenericModule;
-import dagger.functional.sub.Exposed;
-import dagger.functional.sub.PublicSubclass;
-import java.util.Arrays;
-import java.util.List;
-import javax.inject.Provider;
-
-@Component(modules = {ChildDoubleModule.class, ChildIntegerModule.class, NongenericModule.class})
-interface GenericComponent {
- ReferencesGeneric referencesGeneric();
- GenericDoubleReferences<A> doubleGenericA();
- GenericDoubleReferences<B> doubleGenericB();
- ComplexGenerics complexGenerics();
- GenericNoDeps<A> noDepsA();
- GenericNoDeps<B> noDepsB();
-
- void injectA(GenericChild<A> childA);
- void injectB(GenericChild<B> childB);
-
- Exposed exposed();
- PublicSubclass publicSubclass();
-
- Iterable<Integer> iterableInt();
- Iterable<Double> iterableDouble();
-
- Provider<List<String>> stringsProvider(); // b/71595104
-
- // b/71595104
- @Module
- abstract class GenericModule<T> {
- // Note that for subclasses that use String for T, this factory will still need two
- // Provider<String> framework dependencies.
- @Provides
- List<T> list(T t, String string) {
- return Arrays.asList(t);
- }
- }
-
- // b/71595104
- @Module
- class NongenericModule extends GenericModule<String> {
- @Provides
- static String string() {
- return "string";
- }
- }
-}
diff --git a/javatests/dagger/functional/GenericDoubleReferences.java b/javatests/dagger/functional/GenericDoubleReferences.java
deleted file mode 100644
index ff79a98..0000000
--- a/javatests/dagger/functional/GenericDoubleReferences.java
+++ /dev/null
@@ -1,33 +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.functional;
-
-import javax.inject.Inject;
-
-class GenericDoubleReferences<T> {
- final T t;
- final T t2;
- final Thing a;
- final Thing a2;
-
- @Inject GenericDoubleReferences(T t, Thing a, T t2, Thing a2) {
- this.t = t;
- this.a = a;
- this.t2 = t2;
- this.a2 = a2;
- }
-}
diff --git a/javatests/dagger/functional/GenericNoDeps.java b/javatests/dagger/functional/GenericNoDeps.java
deleted file mode 100644
index c3f38b4..0000000
--- a/javatests/dagger/functional/GenericNoDeps.java
+++ /dev/null
@@ -1,25 +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.functional;
-
-import javax.inject.Inject;
-
-class GenericNoDeps<T> {
-
- @Inject GenericNoDeps() {}
-
-}
diff --git a/javatests/dagger/functional/GenericParent.java b/javatests/dagger/functional/GenericParent.java
deleted file mode 100644
index 13f9e2f..0000000
--- a/javatests/dagger/functional/GenericParent.java
+++ /dev/null
@@ -1,51 +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.functional;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-class GenericParent<X, Y> {
-
- Provider<X> registeredX;
- Y registeredY;
- B registeredB;
- Parameterized<Y> registerParameterizedOfY;
-
- @Inject GenericParent() {}
-
- @Inject Provider<X> x;
- @Inject Y y;
- @Inject B b;
- @Inject Parameterized<X> parameterizedOfX;
-
- @Inject
- void registerX(Provider<X> x) {
- this.registeredX = x;
- }
- @Inject void registerY(Y y) { this.registeredY = y; }
- @Inject void registerB(B b) { this.registeredB = b; }
- @Inject void registerParameterizedOfY(Parameterized<Y> parameterizedOfY) {
- this.registerParameterizedOfY = parameterizedOfY;
- }
-
- static class Parameterized<P> {
- @Inject P p;
-
- @Inject Parameterized() {}
- }
-}
diff --git a/javatests/dagger/functional/GenericTest.java b/javatests/dagger/functional/GenericTest.java
deleted file mode 100644
index 3e4a271..0000000
--- a/javatests/dagger/functional/GenericTest.java
+++ /dev/null
@@ -1,160 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-
-import dagger.functional.sub.Exposed;
-import dagger.functional.sub.PublicSubclass;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class GenericTest {
-
- @Test public void testGenericComponentCreate() {
- GenericComponent component = DaggerGenericComponent.create();
- assertThat(component).isNotNull();
- }
-
- @Test public void testGenericSimpleReferences() {
- GenericComponent component = DaggerGenericComponent.create();
- assertThat(component.referencesGeneric().genericA.t).isNotNull();
- }
-
- @Test public void testGenericDoubleReferences() {
- GenericComponent component = DaggerGenericComponent.create();
- GenericDoubleReferences<A> doubleA = component.doubleGenericA();
- assertThat(doubleA.a).isNotNull();
- assertThat(doubleA.a2).isNotNull();
- assertThat(doubleA.t).isNotNull();
- assertThat(doubleA.t2).isNotNull();
-
- GenericDoubleReferences<B> doubleB = component.doubleGenericB();
- assertThat(doubleB.a).isNotNull();
- assertThat(doubleB.a2).isNotNull();
- assertThat(doubleB.t).isNotNull();
- assertThat(doubleB.t2).isNotNull();
- }
-
- @Test public void complexGenerics() {
- GenericComponent component = DaggerGenericComponent.create();
- // validate these can be called w/o exceptions.
- component.complexGenerics();
- }
-
- @Test public void noDepsGenerics() {
- GenericComponent component = DaggerGenericComponent.create();
- // validate these can be called w/o exceptions.
- component.noDepsA();
- component.noDepsB();
- }
-
- @Test public void boundedGenerics() {
- BoundedGenericModule expected = new BoundedGenericModule();
- BoundedGenericComponent component = DaggerBoundedGenericComponent.create();
- BoundedGenerics<Integer, ArrayList<String>, LinkedList<CharSequence>, Integer, List<Integer>>
- b1 = component.bounds1();
- assertEquals(expected.provideInteger(), b1.a);
- assertEquals(expected.provideArrayListString(), b1.b);
- assertEquals(expected.provideLinkedListCharSeq(), b1.c);
- assertEquals(expected.provideInteger(), b1.d);
- assertEquals(expected.provideListOfInteger(), b1.e);
-
- BoundedGenerics<Double, LinkedList<String>, LinkedList<Comparable<String>>, Double, Set<Double>>
- b2 = component.bounds2();
- assertEquals(expected.provideDouble(), b2.a);
- assertEquals(expected.provideLinkedListString(), b2.b);
- assertEquals(expected.provideArrayListOfComparableString(), b2.c);
- assertEquals(expected.provideDouble(), b2.d);
- assertEquals(expected.provideSetOfDouble(), b2.e);
- }
-
- @Test public void membersInjections() {
- GenericComponent component = DaggerGenericComponent.create();
- GenericChild<A> childA = new GenericChild<A>();
- component.injectA(childA);
- assertThat(childA.a).isNotNull();
- assertThat(childA.b).isNotNull();
- assertThat(childA.registeredA).isNotNull();
- assertThat(childA.registeredB).isNotNull();
- assertThat(childA.registeredT).isNotNull();
- assertThat(childA.registeredX).isNotNull();
- assertThat(childA.registeredY).isNotNull();
-
- GenericChild<B> childB = new GenericChild<B>();
- component.injectB(childB);
- assertThat(childB.a).isNotNull();
- assertThat(childB.b).isNotNull();
- assertThat(childB.registeredA).isNotNull();
- assertThat(childB.registeredB).isNotNull();
- assertThat(childB.registeredT).isNotNull();
- assertThat(childB.registeredX).isNotNull();
- assertThat(childB.registeredY).isNotNull();
- }
-
- @Test public void packagePrivateTypeParameterDependencies() {
- GenericComponent component = DaggerGenericComponent.create();
- Exposed exposed = component.exposed();
- assertThat(exposed.gpp.t).isNotNull();
- assertThat(exposed.gpp2).isNotNull();
- }
-
- @SuppressWarnings("rawtypes")
- @Test public void publicSubclassWithPackagePrivateTypeParameterOfSuperclass() {
- GenericComponent component = DaggerGenericComponent.create();
- PublicSubclass publicSubclass = component.publicSubclass();
- assertThat(((Generic)publicSubclass).t).isNotNull();
- }
-
- @Test public void singletonScopesAppliesToEachResolvedType() {
- SingletonGenericComponent component = DaggerSingletonGenericComponent.create();
- ScopedGeneric<A> a = component.scopedGenericA();
- assertThat(a).isSameInstanceAs(component.scopedGenericA());
- assertThat(a.t).isNotNull();
-
- ScopedGeneric<B> b = component.scopedGenericB();
- assertThat(b).isSameInstanceAs(component.scopedGenericB());
- assertThat(b.t).isNotNull();
-
- assertThat(a).isNotSameInstanceAs(b);
- }
-
- @Test // See https://github.com/google/dagger/issues/671
- public void scopedSimpleGenerics() {
- SingletonGenericComponent component = DaggerSingletonGenericComponent.create();
- ScopedSimpleGeneric<A> a = component.scopedSimpleGenericA();
- assertThat(a).isSameInstanceAs(component.scopedSimpleGenericA());
-
- ScopedSimpleGeneric<B> b = component.scopedSimpleGenericB();
- assertThat(b).isSameInstanceAs(component.scopedSimpleGenericB());
-
- assertThat(a).isNotSameInstanceAs(b);
- }
-
- @Test public void genericModules() {
- GenericComponent component = DaggerGenericComponent.create();
- assertThat(component.iterableInt()).containsExactly(1, 2).inOrder();
- assertThat(component.iterableDouble()).containsExactly(3d, 4d).inOrder();
- }
-}
diff --git a/javatests/dagger/functional/InjectedThing.java b/javatests/dagger/functional/InjectedThing.java
deleted file mode 100644
index 3041fb0..0000000
--- a/javatests/dagger/functional/InjectedThing.java
+++ /dev/null
@@ -1,233 +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.functional;
-
-import dagger.Lazy;
-import dagger.MembersInjector;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-@SuppressWarnings("unused")
-final class InjectedThing {
- @Inject byte primitiveByte;
- @Inject char primitiveChar;
- @Inject short primitiveShort;
- @Inject int primitiveInt;
- @Inject long primitiveLong;
- @Inject boolean primitiveBoolean;
- @Inject float primitiveFloat;
- @Inject double primitiveDouble;
-
- @Inject Provider<Byte> byteProvider;
- @Inject Provider<Character> charProvider;
- @Inject Provider<Short> shortProvider;
- @Inject Provider<Integer> intProvider;
- @Inject Provider<Long> longProvider;
- @Inject Provider<Boolean> booleanProvider;
- @Inject Provider<Float> floatProvider;
- @Inject Provider<Double> doubleProvider;
-
- @Inject Lazy<Byte> lazyByte;
- @Inject Lazy<Character> lazyChar;
- @Inject Lazy<Short> lazyShort;
- @Inject Lazy<Integer> lazyInt;
- @Inject Lazy<Long> lazyLong;
- @Inject Lazy<Boolean> lazyBoolean;
- @Inject Lazy<Float> lazyFloat;
- @Inject Lazy<Double> lazyDouble;
-
- @Inject Byte boxedBype;
- @Inject Character boxedChar;
- @Inject Short boxedShort;
- @Inject Integer boxedInt;
- @Inject Long boxedLong;
- @Inject Boolean boxedBoolean;
- @Inject Float boxedFloat;
- @Inject Double boxedDouble;
-
- @Inject byte[] byteArray;
- @Inject char[] charArray;
- @Inject short[] shortArray;
- @Inject int[] intArray;
- @Inject long[] longArray;
- @Inject boolean[] booleanArray;
- @Inject float[] floatArray;
- @Inject double[] doubleArray;
-
- @Inject Provider<byte[]> byteArrayProvider;
- @Inject Provider<char[]> charArrayProvider;
- @Inject Provider<short[]> shortArrayProvider;
- @Inject Provider<int[]> intArrayProvider;
- @Inject Provider<long[]> longArrayProvider;
- @Inject Provider<boolean[]> booleanArrayProvider;
- @Inject Provider<float[]> floatArrayProvider;
- @Inject Provider<double[]> doubleArrayProvider;
-
- @Inject Lazy<byte[]> lazyByteArray;
- @Inject Lazy<char[]> lazyCharArray;
- @Inject Lazy<short[]> lazyShortArray;
- @Inject Lazy<int[]> lazyIntArray;
- @Inject Lazy<long[]> lazyLongArray;
- @Inject Lazy<boolean[]> lazyBooleanArray;
- @Inject Lazy<float[]> lazy;
- @Inject Lazy<double[]> lazyDoubleArray;
-
- @Inject Thing thing;
- @Inject Provider<Thing> thingProvider;
- @Inject Lazy<Thing> lazyThing;
- @Inject Provider<Lazy<Thing>> lazyThingProvider;
- @Inject MembersInjector<Thing> thingMembersInjector;
-
- @Inject InjectedThing(
- byte primitiveByte,
- char primitiveChar,
- short primitiveShort,
- int primitiveInt,
- long primitiveLong,
- boolean primitiveBoolean,
- float primitiveFloat,
- double primitiveDouble,
-
- Provider<Byte> byteProvider,
- Provider<Character> charProvider,
- Provider<Short> shortProvider,
- Provider<Integer> intProvider,
- Provider<Long> longProvider,
- Provider<Boolean> booleanProvider,
- Provider<Float> floatProvider,
- Provider<Double> doubleProvider,
-
- Lazy<Byte> lazyByte,
- Lazy<Character> lazyChar,
- Lazy<Short> lazyShort,
- Lazy<Integer> lazyInt,
- Lazy<Long> lazyLong,
- Lazy<Boolean> lazyBoolean,
- Lazy<Float> lazyFloat,
- Lazy<Double> lazyDouble,
-
- Byte boxedBype,
- Character boxedChar,
- Short boxedShort,
- Integer boxedInt,
- Long boxedLong,
- Boolean boxedBoolean,
- Float boxedFloat,
- Double boxedDouble,
-
- byte[] byteArray,
- char[] charArray,
- short[] shortArray,
- int[] intArray,
- long[] longArray,
- boolean[] booleanArray,
- float[] floatArray,
- double[] doubleArray,
-
- Provider<byte[]> byteArrayProvider,
- Provider<char[]> charArrayProvider,
- Provider<short[]> shortArrayProvider,
- Provider<int[]> intArrayProvider,
- Provider<long[]> longArrayProvider,
- Provider<boolean[]> booleanArrayProvider,
- Provider<float[]> floatArrayProvider,
- Provider<double[]> doubleArrayProvider,
-
- Lazy<byte[]> lazyByteArray,
- Lazy<char[]> lazyCharArray,
- Lazy<short[]> lazyShortArray,
- Lazy<int[]> lazyIntArray,
- Lazy<long[]> lazyLongArray,
- Lazy<boolean[]> lazyBooleanArray,
- Lazy<float[]> lazy,
- Lazy<double[]> lazyDoubleArray,
-
- Thing thing,
- Provider<Thing> thingProvider,
- Lazy<Thing> lazyThing,
- Provider<Lazy<Thing>> lazyThingProvider,
- MembersInjector<Thing> thingMembersInjector) {}
-
- @Inject void primitiveByte(byte primitiveByte) {}
- @Inject void primitiveChar(char primitiveChar) {}
- @Inject void primitiveShort(short primitiveShort) {}
- @Inject void primitiveInt(int primitiveInt) {}
- @Inject void primitiveLong(long primitiveLong) {}
- @Inject void primitiveBoolean(boolean primitiveBoolean) {}
- @Inject void primitiveFloat(float primitiveFloat) {}
- @Inject void primitiveDouble(double primitiveDouble) {}
-
- @Inject void byteProvider(Provider<Byte> byteProvider) {}
- @Inject void charProvider(Provider<Character> charProvider) {}
- @Inject void shortProvider(Provider<Short> shortProvider) {}
- @Inject void intProvider(Provider<Integer> intProvider) {}
- @Inject void longProvider(Provider<Long> longProvider) {}
- @Inject void booleanProvider(Provider<Boolean> booleanProvider) {}
- @Inject void floatProvider(Provider<Float> floatProvider) {}
- @Inject void doubleProvider(Provider<Double> doubleProvider) {}
-
- @Inject void lazyByte(Lazy<Byte> lazyByte) {}
- @Inject void lazyChar(Lazy<Character> lazyChar) {}
- @Inject void lazyShort(Lazy<Short> lazyShort) {}
- @Inject void lazyInt(Lazy<Integer> lazyInt) {}
- @Inject void lazyLong(Lazy<Long> lazyLong) {}
- @Inject void lazyBoolean(Lazy<Boolean> lazyBoolean) {}
- @Inject void lazyFloat(Lazy<Float> lazyFloat) {}
- @Inject void lazyDouble(Lazy<Double> lazyDouble) {}
-
- @Inject void boxedBype(Byte boxedBype) {}
- @Inject void boxedChar(Character boxedChar) {}
- @Inject void boxedShort(Short boxedShort) {}
- @Inject void boxedInt(Integer boxedInt) {}
- @Inject void boxedLong(Long boxedLong) {}
- @Inject void boxedBoolean(Boolean boxedBoolean) {}
- @Inject void boxedFloat(Float boxedFloat) {}
- @Inject void boxedDouble(Double boxedDouble) {}
-
- @Inject void byteArray(byte[] byteArray) {}
- @Inject void charArray(char[] charArray) {}
- @Inject void shortArray(short[] shortArray) {}
- @Inject void intArray(int[] intArray) {}
- @Inject void longArray(long[] longArray) {}
- @Inject void booleanArray(boolean[] booleanArray) {}
- @Inject void floatArray(float[] floatArray) {}
- @Inject void doubleArray(double[] doubleArray) {}
-
- @Inject void byteArrayProvider(Provider<byte[]> byteArrayProvider) {}
- @Inject void charArrayProvider(Provider<char[]> charArrayProvider) {}
- @Inject void shortArrayProvider(Provider<short[]> shortArrayProvider) {}
- @Inject void intArrayProvider(Provider<int[]> intArrayProvider) {}
- @Inject void longArrayProvider(Provider<long[]> longArrayProvider) {}
- @Inject void booleanArrayProvider(Provider<boolean[]> booleanArrayProvider) {}
- @Inject void floatArrayProvider(Provider<float[]> floatArrayProvider) {}
- @Inject void doubleArrayProvider(Provider<double[]> doubleArrayProvider) {}
-
- @Inject void lazyByteArray(Lazy<byte[]> lazyByteArray) {}
- @Inject void lazyCharArray(Lazy<char[]> lazyCharArray) {}
- @Inject void lazyShortArray(Lazy<short[]> lazyShortArray) {}
- @Inject void lazyIntArray(Lazy<int[]> lazyIntArray) {}
- @Inject void lazyLongArray(Lazy<long[]> lazyLongArray) {}
- @Inject void lazyBooleanArray(Lazy<boolean[]> lazyBooleanArray) {}
- @Inject void lazy(Lazy<float[]> lazy) {}
- @Inject void lazyThingProvider(Provider<Lazy<Thing>> lazyThingProvider) {}
- @Inject void lazyDoubleArray(Lazy<double[]> lazyDoubleArray) {}
-
- @Inject void thing(Thing thing) {}
- @Inject void thingProvider(Provider<Thing> thingProvider) {}
- @Inject void lazyThing(Lazy<Thing> lazyThing) {}
- @Inject void thingMembersInjector(MembersInjector<Thing> thingMembersInjector) {}
-}
diff --git a/javatests/dagger/functional/Injector.java b/javatests/dagger/functional/Injector.java
deleted file mode 100644
index d001f93..0000000
--- a/javatests/dagger/functional/Injector.java
+++ /dev/null
@@ -1,33 +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.functional;
-
-import dagger.Lazy;
-import dagger.MembersInjector;
-import javax.inject.Provider;
-
-/**
- * A simple interface that exercises all forms of injection for a given type.
- */
-interface Injector<T> {
- T instance();
- Provider<T> provider();
- Lazy<T> lazy();
- MembersInjector<T> membersInjector();
- void injectMembers(T t);
- T injectMembersAndReturn(T t);
-}
diff --git a/javatests/dagger/functional/LazyMaps.java b/javatests/dagger/functional/LazyMaps.java
deleted file mode 100644
index eeb1368..0000000
--- a/javatests/dagger/functional/LazyMaps.java
+++ /dev/null
@@ -1,76 +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.functional;
-
-import dagger.Component;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-/**
- * Bindings that use {@code Lazy<T>} as the value in a multibound map. A regression was uncovered
- * when using {@code MapType.valuesAreFrameworkType()}, which treats {@link Lazy} as a framework
- * type and incorrectly suggested {@link dagger.internal.MapProviderFactory} for a {@code Map<K,
- * Lazy<V>>} instead of a plain {@link dagger.internal.MapFactory}. See b/65084589.
- */
-class LazyMaps {
- @Module
- abstract static class TestModule {
- @Provides
- @Singleton
- static AtomicInteger provideAtomicInteger() {
- return new AtomicInteger();
- }
-
- @Provides
- static String provideString(AtomicInteger atomicInteger) {
- return "value-" + atomicInteger.incrementAndGet();
- }
-
- @Provides
- @IntoMap
- @StringKey("key")
- static Lazy<String> mapContribution(Lazy<String> lazy) {
- return lazy;
- }
-
- /* TODO(b/65118638) Replace once @Binds @IntoMap Lazy<T> methods work properly.
- @Binds
- @IntoMap
- @StringKey("binds-key")
- abstract Lazy<String> mapContributionAsBinds(Lazy<String> lazy);
- */
- }
-
- @Singleton
- @Component(modules = TestModule.class)
- interface TestComponent {
- Map<String, Lazy<String>> mapOfLazy();
-
- Map<String, Provider<Lazy<String>>> mapOfProviderOfLazy();
-
- Provider<Map<String, Lazy<String>>> providerForMapOfLazy();
-
- Provider<Map<String, Provider<Lazy<String>>>> providerForMapOfProviderOfLazy();
- }
-}
diff --git a/javatests/dagger/functional/LazyMapsTest.java b/javatests/dagger/functional/LazyMapsTest.java
deleted file mode 100644
index a441653..0000000
--- a/javatests/dagger/functional/LazyMapsTest.java
+++ /dev/null
@@ -1,52 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Lazy;
-import dagger.functional.LazyMaps.TestComponent;
-import java.util.Map;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link LazyMaps}. */
-@RunWith(JUnit4.class)
-public class LazyMapsTest {
- @Test
- public void mapOfLazies() {
- TestComponent component = DaggerLazyMaps_TestComponent.create();
- Map<String, Lazy<String>> laziesMap = component.mapOfLazy();
-
- String firstGet = laziesMap.get("key").get();
- assertThat(firstGet).isEqualTo("value-1");
- assertThat(firstGet).isSameInstanceAs(laziesMap.get("key").get());
-
- assertThat(component.mapOfLazy().get("key").get()).isEqualTo("value-2");
- }
-
- @Test
- public void mapOfProviderOfLaziesReturnsDifferentLazy() {
- TestComponent component = DaggerLazyMaps_TestComponent.create();
- Map<String, Provider<Lazy<String>>> providersOfLaziesMap = component.mapOfProviderOfLazy();
-
- assertThat(providersOfLaziesMap.get("key").get().get())
- .isNotEqualTo(providersOfLaziesMap.get("key").get().get());
- }
-}
diff --git a/javatests/dagger/functional/ModuleCycles.java b/javatests/dagger/functional/ModuleCycles.java
deleted file mode 100644
index 9df6685..0000000
--- a/javatests/dagger/functional/ModuleCycles.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.functional;
-
-import dagger.Component;
-import dagger.Module;
-
-final class ModuleCycles {
- @Module(includes = ModuleB.class)
- interface ModuleA {}
-
- @Module(includes = ModuleA.class)
- interface ModuleB {}
-
- @Component(modules = ModuleA.class)
- interface CycleComponent {}
-}
diff --git a/javatests/dagger/functional/ModuleIncludesCollectedFromModuleSuperclasses.java b/javatests/dagger/functional/ModuleIncludesCollectedFromModuleSuperclasses.java
deleted file mode 100644
index fb18b6d..0000000
--- a/javatests/dagger/functional/ModuleIncludesCollectedFromModuleSuperclasses.java
+++ /dev/null
@@ -1,65 +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.functional;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * This tests that @Module.includes are traversed for supertypes of a module.
- */
-final class ModuleIncludesCollectedFromModuleSuperclasses {
- @Component(modules = TopLevelModule.class)
- interface C {
- Foo<String> foo();
- int includedInTopLevelModule();
- String includedFromModuleInheritance();
- }
-
- @Module(includes = IncludedTopLevel.class)
- static class TopLevelModule extends FooModule<String> {}
-
- static class Foo<T> {}
-
- @Module(includes = IncludedFromModuleInheritance.class)
- abstract static class FooModule<T> extends FooCreator {
- @Provides Foo<T> fooOfT() {
- return createFoo();
- }
- }
-
- static class FooCreator {
- <T> Foo<T> createFoo() {
- return new Foo<T>();
- }
- }
-
- @Module
- static class IncludedTopLevel {
- @Provides int i() {
- return 123;
- }
- }
-
- @Module
- static class IncludedFromModuleInheritance {
- @Provides String inheritedProvision() {
- return "inherited";
- }
- }
-}
diff --git a/javatests/dagger/functional/ModuleWithConflictingNames.java b/javatests/dagger/functional/ModuleWithConflictingNames.java
deleted file mode 100644
index 43dd58e..0000000
--- a/javatests/dagger/functional/ModuleWithConflictingNames.java
+++ /dev/null
@@ -1,48 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Module with bindings that might result in generated factories with conflicting field and
- * parameter names.
- */
-@Module
-final class ModuleWithConflictingNames {
- @Provides
- static Object object(int foo, Provider<String> fooProvider) {
- return foo + fooProvider.get();
- }
-
- /**
- * A class that might result in a generated factory with conflicting field and parameter names.
- */
- static class InjectedClassWithConflictingNames {
- final int foo;
- final Provider<String> fooProvider;
-
- @Inject
- InjectedClassWithConflictingNames(int foo, Provider<String> fooProvider) {
- this.foo = foo;
- this.fooProvider = fooProvider;
- }
- }
-}
diff --git a/javatests/dagger/functional/MultibindingComponent.java b/javatests/dagger/functional/MultibindingComponent.java
deleted file mode 100644
index 60ed5cf..0000000
--- a/javatests/dagger/functional/MultibindingComponent.java
+++ /dev/null
@@ -1,70 +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.functional;
-
-import dagger.Component;
-import dagger.functional.sub.ContributionsModule;
-import dagger.multibindings.StringKey;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Named;
-import javax.inject.Provider;
-
-@Component(
- modules = {MultibindingModule.class, MultibindsModule.class, ContributionsModule.class},
- dependencies = MultibindingDependency.class
-)
-interface MultibindingComponent {
- Map<String, String> map();
- Map<String, String[]> mapOfArrays();
- Map<String, Provider<String>> mapOfProviders();
- Set<String> mapKeys();
- Collection<String> mapValues();
- Set<Integer> set();
- Map<NestedAnnotationContainer.NestedWrappedKey, String> nestedKeyMap();
- Map<Class<? extends Number>, String> numberClassKeyMap();
- Map<Class<?>, String> classKeyMap();
- Map<Long, String> longKeyMap();
- Map<Integer, String> integerKeyMap();
- Map<Short, String> shortKeyMap();
- Map<Byte, String> byteKeyMap();
- Map<Boolean, String> booleanKeyMap();
- Map<Character, String> characterKeyMap();
- Map<StringKey, String> unwrappedAnnotationKeyMap();
- Map<WrappedAnnotationKey, String> wrappedAnnotationKeyMap();
- @Named("complexQualifier") Set<String> complexQualifierStringSet();
- Set<Object> emptySet();
-
- @Named("complexQualifier")
- Set<Object> emptyQualifiedSet();
-
- Map<String, Object> emptyMap();
-
- @Named("complexQualifier")
- Map<String, Object> emptyQualifiedMap();
-
- Set<CharSequence> maybeEmptySet();
-
- @Named("complexQualifier")
- Set<CharSequence> maybeEmptyQualifiedSet();
-
- Map<String, CharSequence> maybeEmptyMap();
-
- @Named("complexQualifier")
- Map<String, CharSequence> maybeEmptyQualifiedMap();
-}
diff --git a/javatests/dagger/functional/MultibindingDependency.java b/javatests/dagger/functional/MultibindingDependency.java
deleted file mode 100644
index 4240051..0000000
--- a/javatests/dagger/functional/MultibindingDependency.java
+++ /dev/null
@@ -1,21 +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.functional;
-
-interface MultibindingDependency {
- double doubleDependency();
-}
diff --git a/javatests/dagger/functional/MultibindingModule.java b/javatests/dagger/functional/MultibindingModule.java
deleted file mode 100644
index e167628..0000000
--- a/javatests/dagger/functional/MultibindingModule.java
+++ /dev/null
@@ -1,242 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.multibindings.LongKey;
-import dagger.multibindings.StringKey;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Named;
-import javax.inject.Provider;
-
-@Module
-class MultibindingModule {
- @Provides
- @IntoMap
- @StringKey("foo")
- static String provideFooKey(@SuppressWarnings("unused") double doubleDependency) {
- return "foo value";
- }
-
- @Provides
- @IntoMap
- @StringKey("bar")
- static String provideBarKey() {
- return "bar value";
- }
-
- @Provides
- @IntoMap
- @StringKey("foo")
- static String[] provideFooArrayValue(@SuppressWarnings("unused") double doubleDependency) {
- return new String[] {"foo1", "foo2"};
- }
-
- @Provides
- @IntoMap
- @StringKey("bar")
- static String[] provideBarArrayValue() {
- return new String[] {"bar1", "bar2"};
- }
-
- @Provides
- @IntoSet
- static int provideFiveToSet() {
- return 5;
- }
-
- @Provides
- @IntoSet
- static int provideSixToSet() {
- return 6;
- }
-
- @Provides
- @ElementsIntoSet
- static Set<Integer> provideElementsIntoSet() {
- Set<Integer> set = new HashSet<>();
- set.add(-101);
- set.add(-102);
- return set;
- }
-
- @Provides
- static Set<String> provideMapKeys(Map<String, Provider<String>> map) {
- return map.keySet();
- }
-
- @Provides
- static Collection<String> provideMapValues(Map<String, String> map) {
- return map.values();
- }
-
- @Provides
- @IntoMap
- @NestedAnnotationContainer.NestedWrappedKey(Integer.class)
- static String valueForInteger() {
- return "integer";
- }
-
- @Provides
- @IntoMap
- @NestedAnnotationContainer.NestedWrappedKey(Long.class)
- static String valueForLong() {
- return "long";
- }
-
- @Provides
- @IntoMap
- @ClassKey(Integer.class)
- static String valueForClassInteger() {
- return "integer";
- }
-
- @Provides
- @IntoMap
- @ClassKey(Long.class)
- static String valueForClassLong() {
- return "long";
- }
-
- @Provides
- @IntoMap
- @NumberClassKey(BigDecimal.class)
- static String valueForNumberClassBigDecimal() {
- return "bigdecimal";
- }
-
- @Provides
- @IntoMap
- @NumberClassKey(BigInteger.class)
- static String valueForNumberClassBigInteger() {
- return "biginteger";
- }
-
- @Provides
- @IntoMap
- @LongKey(100)
- static String valueFor100Long() {
- return "100 long";
- }
-
- @Provides
- @IntoMap
- @IntKey(100)
- static String valueFor100Int() {
- return "100 int";
- }
-
- @Provides
- @IntoMap
- @ShortKey(100)
- static String valueFor100Short() {
- return "100 short";
- }
-
- @Provides
- @IntoMap
- @ByteKey(100)
- static String valueFor100Byte() {
- return "100 byte";
- }
-
- @Provides
- @IntoMap
- @BooleanKey(true)
- static String valueForTrue() {
- return "true";
- }
-
- @Provides
- @IntoMap
- @CharKey('a')
- static String valueForA() {
- return "a char";
- }
-
- @Provides
- @IntoMap
- @CharKey('\n')
- static String valueForNewline() {
- return "newline char";
- }
-
- @Provides
- @IntoMap
- @UnwrappedAnnotationKey(@StringKey("foo\n"))
- static String valueForUnwrappedAnnotationKeyFoo() {
- return "foo annotation";
- }
-
- @Provides
- @IntoMap
- @WrappedAnnotationKey(
- value = @StringKey("foo"),
- integers = {1, 2, 3},
- annotations = {},
- classes = {Long.class, Integer.class}
- )
- static String valueForWrappedAnnotationKeyFoo() {
- return "wrapped foo annotation";
- }
-
- @Provides
- @IntoSet
- @Named("complexQualifier")
- static String valueForComplexQualifierSet() {
- return "foo";
- }
-
- @Provides
- @IntoSet
- static CharSequence setContribution() {
- return "foo";
- }
-
- @Provides
- @IntoSet
- @Named("complexQualifier")
- static CharSequence qualifiedSetContribution() {
- return "qualified foo";
- }
-
- @Provides
- @IntoMap
- @StringKey("key")
- static CharSequence mapContribution() {
- return "foo value";
- }
-
- @Provides
- @IntoMap
- @Named("complexQualifier")
- @StringKey("key")
- static CharSequence qualifiedMapContribution() {
- return "qualified foo value";
- }
-}
diff --git a/javatests/dagger/functional/MultibindingTest.java b/javatests/dagger/functional/MultibindingTest.java
deleted file mode 100644
index d99e46d..0000000
--- a/javatests/dagger/functional/MultibindingTest.java
+++ /dev/null
@@ -1,202 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.auto.value.AutoAnnotation;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.StringKey;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Map;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link MultibindingComponent}. */
-@RunWith(JUnit4.class)
-public class MultibindingTest {
-
- private final MultibindingComponent multibindingComponent =
- DaggerMultibindingComponent.builder().multibindingDependency(() -> 0.0).build();
-
- @Test public void map() {
- Map<String, String> map = multibindingComponent.map();
- assertThat(map).hasSize(2);
- assertThat(map).containsEntry("foo", "foo value");
- assertThat(map).containsEntry("bar", "bar value");
- }
-
- @Test public void mapOfArrays() {
- Map<String, String[]> map = multibindingComponent.mapOfArrays();
- assertThat(map).hasSize(2);
- assertThat(map).containsKey("foo");
- assertThat(map.get("foo")).asList().containsExactly("foo1", "foo2").inOrder();
- assertThat(map).containsKey("bar");
- assertThat(map.get("bar")).asList().containsExactly("bar1", "bar2").inOrder();
- }
-
- @Test public void mapOfProviders() {
- Map<String, Provider<String>> mapOfProviders = multibindingComponent.mapOfProviders();
- assertThat(mapOfProviders).hasSize(2);
- assertThat(mapOfProviders.get("foo").get()).isEqualTo("foo value");
- assertThat(mapOfProviders.get("bar").get()).isEqualTo("bar value");
- }
-
- @Test public void mapKeysAndValues() {
- assertThat(multibindingComponent.mapKeys())
- .containsExactly("foo", "bar");
- assertThat(multibindingComponent.mapValues())
- .containsExactly("foo value", "bar value");
- }
-
- @Test public void nestedKeyMap() {
- assertThat(multibindingComponent.nestedKeyMap())
- .containsExactly(
- nestedWrappedKey(Integer.class), "integer", nestedWrappedKey(Long.class), "long");
- }
-
- @Test
- public void unwrappedAnnotationKeyMap() {
- assertThat(multibindingComponent.unwrappedAnnotationKeyMap())
- .containsExactly(testStringKey("foo\n"), "foo annotation");
- }
-
- @Test
- public void wrappedAnnotationKeyMap() {
- @SuppressWarnings("unchecked")
- Class<? extends Number>[] classes = new Class[] {Long.class, Integer.class};
- assertThat(multibindingComponent.wrappedAnnotationKeyMap())
- .containsExactly(
- testWrappedAnnotationKey(
- testStringKey("foo"), new int[] {1, 2, 3}, new ClassKey[] {}, classes),
- "wrapped foo annotation");
- }
-
- @Test
- public void booleanKeyMap() {
- assertThat(multibindingComponent.booleanKeyMap()).containsExactly(true, "true");
- }
-
- @Test
- public void byteKeyMap() {
- assertThat(multibindingComponent.byteKeyMap()).containsExactly((byte) 100, "100 byte");
- }
-
- @Test
- public void charKeyMap() {
- assertThat(multibindingComponent.characterKeyMap())
- .containsExactly('a', "a char", '\n', "newline char");
- }
-
- @Test
- public void classKeyMap() {
- assertThat(multibindingComponent.classKeyMap())
- .containsExactly(Integer.class, "integer", Long.class, "long");
- }
-
- @Test
- public void numberClassKeyMap() {
- assertThat(multibindingComponent.numberClassKeyMap())
- .containsExactly(BigDecimal.class, "bigdecimal", BigInteger.class, "biginteger");
- }
-
- @Test
- public void intKeyMap() {
- assertThat(multibindingComponent.integerKeyMap()).containsExactly(100, "100 int");
- }
-
- @Test
- public void longKeyMap() {
- assertThat(multibindingComponent.longKeyMap()).containsExactly((long) 100, "100 long");
- }
-
- @Test
- public void shortKeyMap() {
- assertThat(multibindingComponent.shortKeyMap()).containsExactly((short) 100, "100 short");
- }
-
- @Test public void setBindings() {
- assertThat(multibindingComponent.set())
- .containsExactly(-90, -17, -1, 5, 6, 832, 1742, -101, -102);
- }
-
- @Test
- public void complexQualifierSet() {
- assertThat(multibindingComponent.complexQualifierStringSet()).containsExactly("foo");
- }
-
- @Test
- public void emptySet() {
- assertThat(multibindingComponent.emptySet()).isEmpty();
- }
-
- @Test
- public void emptyQualifiedSet() {
- assertThat(multibindingComponent.emptyQualifiedSet()).isEmpty();
- }
-
- @Test
- public void emptyMap() {
- assertThat(multibindingComponent.emptyMap()).isEmpty();
- }
-
- @Test
- public void emptyQualifiedMap() {
- assertThat(multibindingComponent.emptyQualifiedMap()).isEmpty();
- }
-
- @Test
- public void maybeEmptySet() {
- assertThat(multibindingComponent.maybeEmptySet()).containsExactly("foo");
- }
-
- @Test
- public void maybeEmptyQualifiedSet() {
- assertThat(multibindingComponent.maybeEmptyQualifiedSet()).containsExactly("qualified foo");
- }
-
- @Test
- public void maybeEmptyMap() {
- assertThat(multibindingComponent.maybeEmptyMap()).containsEntry("key", "foo value");
- }
-
- @Test
- public void maybeEmptyQualifiedMap() {
- assertThat(multibindingComponent.maybeEmptyQualifiedMap())
- .containsEntry("key", "qualified foo value");
- }
-
- @AutoAnnotation
- static StringKey testStringKey(String value) {
- return new AutoAnnotation_MultibindingTest_testStringKey(value);
- }
-
- @AutoAnnotation
- static NestedAnnotationContainer.NestedWrappedKey nestedWrappedKey(Class<?> value) {
- return new AutoAnnotation_MultibindingTest_nestedWrappedKey(value);
- }
-
- @AutoAnnotation
- static WrappedAnnotationKey testWrappedAnnotationKey(
- StringKey value, int[] integers, ClassKey[] annotations, Class<? extends Number>[] classes) {
- return new AutoAnnotation_MultibindingTest_testWrappedAnnotationKey(
- value, integers, annotations, classes);
- }
-}
diff --git a/javatests/dagger/functional/MultibindsModule.java b/javatests/dagger/functional/MultibindsModule.java
deleted file mode 100644
index 65ba7c8..0000000
--- a/javatests/dagger/functional/MultibindsModule.java
+++ /dev/null
@@ -1,59 +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.functional;
-
-import dagger.Module;
-import dagger.multibindings.Multibinds;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Named;
-
-/**
- * A module that uses {@link Multibinds @Multibinds}-annotated abstract methods to declare
- * multibindings.
- */
-@Module
-abstract class MultibindsModule {
-
- @Multibinds
- abstract Set<Object> emptySet();
-
- @Multibinds
- abstract Map<String, Object> emptyMap();
-
- @Multibinds
- abstract Set<CharSequence> set();
-
- @Multibinds
- abstract Map<String, CharSequence> map();
-
- @Multibinds
- @Named("complexQualifier")
- abstract Set<Object> emptyQualifiedSet();
-
- @Multibinds
- @Named("complexQualifier")
- abstract Map<String, Object> emptyQualifiedMap();
-
- @Multibinds
- @Named("complexQualifier")
- abstract Set<CharSequence> qualifiedSet();
-
- @Multibinds
- @Named("complexQualifier")
- abstract Map<String, CharSequence> qualifiedMap();
-}
diff --git a/javatests/dagger/functional/NeedsFactory.java b/javatests/dagger/functional/NeedsFactory.java
deleted file mode 100644
index 2ea01ec..0000000
--- a/javatests/dagger/functional/NeedsFactory.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.functional;
-
-import com.google.auto.factory.AutoFactory;
-import javax.inject.Inject;
-
-class NeedsFactory {
- @Inject
- NeedsFactory(@SuppressWarnings("unused") NeedsFactory_SomethingFactory somethingFactory) {}
-
- @AutoFactory
- static class Something {}
-}
-
diff --git a/javatests/dagger/functional/NeedsProviderOfFactory.java b/javatests/dagger/functional/NeedsProviderOfFactory.java
deleted file mode 100644
index efbd73d..0000000
--- a/javatests/dagger/functional/NeedsProviderOfFactory.java
+++ /dev/null
@@ -1,39 +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.functional;
-
-import com.google.auto.factory.AutoFactory;
-import dagger.Component;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-// b/73455487
-class NeedsProviderOfFactory {
- static class InjectsProviderOfFactory {
- @Inject
- InjectsProviderOfFactory(
- Provider<NeedsProviderOfFactory_SomethingFactory> provider) {}
- }
-
- @Component
- interface ExposesFactoryAsProvider {
- InjectsProviderOfFactory injectsProviderOfFactory();
- }
-
- @AutoFactory
- static class Something {}
-}
diff --git a/javatests/dagger/functional/NestedAnnotationContainer.java b/javatests/dagger/functional/NestedAnnotationContainer.java
deleted file mode 100644
index a2b61fa..0000000
--- a/javatests/dagger/functional/NestedAnnotationContainer.java
+++ /dev/null
@@ -1,27 +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.functional;
-
-import dagger.MapKey;
-
-public final class NestedAnnotationContainer {
-
- @MapKey(unwrapValue = false)
- @interface NestedWrappedKey {
- Class<?> value();
- }
-}
diff --git a/javatests/dagger/functional/NestedTest.java b/javatests/dagger/functional/NestedTest.java
deleted file mode 100644
index c1e21b2..0000000
--- a/javatests/dagger/functional/NestedTest.java
+++ /dev/null
@@ -1,36 +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.functional;
-
-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 NestedTest {
- @Test public void nestedFoo() {
- OuterClassFoo.NestedComponent nestedFoo = DaggerOuterClassFoo_NestedComponent.create();
- assertThat(nestedFoo.thing()).isNotNull();
- }
-
- @Test public void nestedBar() {
- OuterClassBar.NestedComponent nestedBar = DaggerOuterClassBar_NestedComponent.create();
- assertThat(nestedBar.injectedThing()).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/NonComponentDependencyComponent.java b/javatests/dagger/functional/NonComponentDependencyComponent.java
deleted file mode 100644
index ee679fa..0000000
--- a/javatests/dagger/functional/NonComponentDependencyComponent.java
+++ /dev/null
@@ -1,48 +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.functional;
-
-import dagger.Component;
-import dagger.functional.sub.OtherThing;
-import javax.inject.Inject;
-
-@Component(dependencies = {NonComponentDependencyComponent.ThingComponent.class})
-interface NonComponentDependencyComponent {
- ThingTwo thingTwo();
-
- static class ThingTwo {
- @SuppressWarnings("unused")
- @Inject
- ThingTwo(
- Thing thing,
- NonComponentDependencyComponent nonComponentDependencyComponent,
- NonComponentDependencyComponent.ThingComponent thingComponent) {}
- }
-
- // A non-component interface which this interface depends upon.
- interface ThingComponent {
- Thing thing();
- }
-
- // The implementation for that interface.
- static class ThingComponentImpl implements ThingComponent {
- @Override
- public Thing thing() {
- return new Thing(new OtherThing(1));
- }
- }
-}
diff --git a/javatests/dagger/functional/NonComponentDependencyTest.java b/javatests/dagger/functional/NonComponentDependencyTest.java
deleted file mode 100644
index 436183f..0000000
--- a/javatests/dagger/functional/NonComponentDependencyTest.java
+++ /dev/null
@@ -1,35 +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.functional;
-
-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 NonComponentDependencyTest {
- @Test public void testThing() {
- NonComponentDependencyComponent component =
- DaggerNonComponentDependencyComponent.builder()
- .thingComponent(new NonComponentDependencyComponent.ThingComponentImpl())
- .build();
- assertThat(component).isNotNull();
- assertThat(component.thingTwo()).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/NullableModule.java b/javatests/dagger/functional/NullableModule.java
deleted file mode 100644
index 406024f..0000000
--- a/javatests/dagger/functional/NullableModule.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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class NullableModule {
- /**
- * A {@code Nullable} that isn't {@link javax.annotation.Nullable}, to ensure that Dagger can be
- * built without depending on JSR-305.
- */
- @interface Nullable {}
-
- @Provides
- @Nullable
- static Object nullObject() {
- return null;
- }
-}
diff --git a/javatests/dagger/functional/NumberClassKey.java b/javatests/dagger/functional/NumberClassKey.java
deleted file mode 100644
index 5909a9f..0000000
--- a/javatests/dagger/functional/NumberClassKey.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.MapKey;
-
-@MapKey(unwrapValue = true)
-@interface NumberClassKey {
- Class<? extends Number> value();
-}
diff --git a/javatests/dagger/functional/OuterClassBar.java b/javatests/dagger/functional/OuterClassBar.java
deleted file mode 100644
index b455595..0000000
--- a/javatests/dagger/functional/OuterClassBar.java
+++ /dev/null
@@ -1,26 +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.functional;
-
-import dagger.Component;
-
-final class OuterClassBar {
- @Component(modules = PrimitivesModule.class)
- interface NestedComponent {
- InjectedThing injectedThing();
- }
-}
diff --git a/javatests/dagger/functional/OuterClassFoo.java b/javatests/dagger/functional/OuterClassFoo.java
deleted file mode 100644
index 213bd80..0000000
--- a/javatests/dagger/functional/OuterClassFoo.java
+++ /dev/null
@@ -1,26 +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.functional;
-
-import dagger.Component;
-
-final class OuterClassFoo {
- @Component(modules = PrimitivesModule.class)
- interface NestedComponent {
- Thing thing();
- }
-}
diff --git a/javatests/dagger/functional/ParentModule.java b/javatests/dagger/functional/ParentModule.java
deleted file mode 100644
index 8bd4fea..0000000
--- a/javatests/dagger/functional/ParentModule.java
+++ /dev/null
@@ -1,44 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-@Module
-abstract class ParentModule<A extends Number & Comparable<A>, B, C extends Iterable<A>> {
- @Provides Iterable<A> provideIterableOfAWithC(A a, C c) {
- List<A> list = new ArrayList<>();
- list.add(a);
- for (A elt : c) {
- list.add(elt);
- }
- return list;
- }
-
- @Provides static char provideNonGenericBindingInParameterizedModule() {
- return 'c';
- }
-
- @Provides
- static List<Set<String>> provideStaticGenericTypeWithNoTypeParametersInParameterizedModule() {
- return new ArrayList<>();
- }
-}
diff --git a/javatests/dagger/functional/PrimitivesModule.java b/javatests/dagger/functional/PrimitivesModule.java
deleted file mode 100644
index 7b7203b..0000000
--- a/javatests/dagger/functional/PrimitivesModule.java
+++ /dev/null
@@ -1,109 +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.functional;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class PrimitivesModule {
- static final byte BOUND_BYTE = -41;
- static final char BOUND_CHAR = 'g';
- static final short BOUND_SHORT = 21840;
- static final int BOUND_INT = 1894833693;
- static final long BOUND_LONG = -4369839828653523584L;
- static final boolean BOUND_BOOLEAN = true;
- static final float BOUND_FLOAT = (float) 0.9964542;
- static final double BOUND_DOUBLE = 0.12681322049667765;
-
- /*
- * While we can't ensure that these constants stay constant, this is a test so we're just going to
- * keep our fingers crossed that we're not going to be jerks.
- */
- static final byte[] BOUND_BYTE_ARRAY = {1, 2, 3};
- static final char[] BOUND_CHAR_ARRAY = {'g', 'a', 'k'};
- static final short[] BOUND_SHORT_ARRAY = {2, 4};
- static final int[] BOUND_INT_ARRAY = {3, 1, 2};
- static final long[] BOUND_LONG_ARRAY = {1, 1, 2, 3, 5};
- static final boolean[] BOUND_BOOLEAN_ARRAY = {false, true, false, false};
- static final float[] BOUND_FLOAT_ARRAY = {(float) 0.1, (float) 0.01, (float) 0.001};
- static final double[] BOUND_DOUBLE_ARRAY = {0.2, 0.02, 0.002};
-
- @Provides static byte provideByte() {
- return BOUND_BYTE;
- }
-
- @Provides static char provideChar() {
- return BOUND_CHAR;
- }
-
- @Provides static short provideShort() {
- return BOUND_SHORT;
- }
-
- @Provides static int provideInt() {
- return BOUND_INT;
- }
-
- @Provides static long provideLong() {
- return BOUND_LONG;
- }
-
- @Provides static boolean provideBoolean() {
- return BOUND_BOOLEAN;
- }
-
- @Provides static float provideFloat() {
- return BOUND_FLOAT;
- }
-
- @Provides static double boundDouble() {
- return BOUND_DOUBLE;
- }
-
- @Provides static byte[] provideByteArray() {
- return BOUND_BYTE_ARRAY;
- }
-
- @Provides static char[] provideCharArray() {
- return BOUND_CHAR_ARRAY;
- }
-
- @Provides static short[] provideShortArray() {
- return BOUND_SHORT_ARRAY;
- }
-
- @Provides static int[] provideIntArray() {
- return BOUND_INT_ARRAY;
- }
-
- @Provides static long[] provideLongArray() {
- return BOUND_LONG_ARRAY;
- }
-
- @Provides static boolean[] provideBooleanArray() {
- return BOUND_BOOLEAN_ARRAY;
- }
-
- @Provides static float[] provideFloatArray() {
- return BOUND_FLOAT_ARRAY;
- }
-
- @Provides static double[] boundDoubleArray() {
- return BOUND_DOUBLE_ARRAY;
- }
-}
diff --git a/javatests/dagger/functional/ReferencesGeneric.java b/javatests/dagger/functional/ReferencesGeneric.java
deleted file mode 100644
index c83dbcc..0000000
--- a/javatests/dagger/functional/ReferencesGeneric.java
+++ /dev/null
@@ -1,27 +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.functional;
-
-import javax.inject.Inject;
-
-class ReferencesGeneric {
- final Generic<A> genericA;
-
- @Inject ReferencesGeneric(Generic<A> genericA) {
- this.genericA = genericA;
- }
-}
diff --git a/javatests/dagger/functional/ReusableTest.java b/javatests/dagger/functional/ReusableTest.java
deleted file mode 100644
index 221b288..0000000
--- a/javatests/dagger/functional/ReusableTest.java
+++ /dev/null
@@ -1,48 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.ComponentWithReusableBindings.ChildOne;
-import dagger.functional.ComponentWithReusableBindings.ChildTwo;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ReusableTest {
- @Test
- public void testReusable() {
- ComponentWithReusableBindings parent = DaggerComponentWithReusableBindings.create();
- ChildOne childOne = parent.childOne();
- ChildTwo childTwo = parent.childTwo();
-
- Object reusableInParent = parent.reusableInParent();
- assertThat(parent.reusableInParent()).isSameInstanceAs(reusableInParent);
- assertThat(childOne.reusableInParent()).isSameInstanceAs(reusableInParent);
- assertThat(childTwo.reusableInParent()).isSameInstanceAs(reusableInParent);
-
- Object reusableFromChildOne = childOne.reusableInChild();
- assertThat(childOne.reusableInChild()).isSameInstanceAs(reusableFromChildOne);
-
- Object reusableFromChildTwo = childTwo.reusableInChild();
- assertThat(childTwo.reusableInChild()).isSameInstanceAs(reusableFromChildTwo);
-
- assertThat(reusableFromChildTwo).isNotSameInstanceAs(reusableFromChildOne);
- }
-}
diff --git a/javatests/dagger/functional/ScopedGeneric.java b/javatests/dagger/functional/ScopedGeneric.java
deleted file mode 100644
index da7e157..0000000
--- a/javatests/dagger/functional/ScopedGeneric.java
+++ /dev/null
@@ -1,28 +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.functional;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton
-class ScopedGeneric<T> {
- final T t;
- @Inject ScopedGeneric(T t) {
- this.t = t;
- }
-}
diff --git a/javatests/dagger/functional/ScopedSimpleGeneric.java b/javatests/dagger/functional/ScopedSimpleGeneric.java
deleted file mode 100644
index 8e48eba..0000000
--- a/javatests/dagger/functional/ScopedSimpleGeneric.java
+++ /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.
- */
-
-package dagger.functional;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * An {@link Inject Inject}ed generic class with no dependencies. Its factory class will have a
- * generic {@code create()} method returning an object whose type parameters cannot be inferred from
- * its arguments. Since it's scoped, the initialization of its field in a generated component must
- * use a raw {@link javax.inject.Provider} in order to allow casting from {@code
- * Provider<ScopedSimpleGeneric<Object>>} to {@code Provider<ScopedSimpleGeneric<Foo>>}.
- */
-@Singleton
-class ScopedSimpleGeneric<T> {
- @Inject
- ScopedSimpleGeneric() {}
-}
diff --git a/javatests/dagger/functional/ShortKey.java b/javatests/dagger/functional/ShortKey.java
deleted file mode 100644
index 3d81d8f..0000000
--- a/javatests/dagger/functional/ShortKey.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.MapKey;
-
-@MapKey(unwrapValue = true)
-@interface ShortKey {
- short value();
-}
diff --git a/javatests/dagger/functional/SingletonGenericComponent.java b/javatests/dagger/functional/SingletonGenericComponent.java
deleted file mode 100644
index d9823cd..0000000
--- a/javatests/dagger/functional/SingletonGenericComponent.java
+++ /dev/null
@@ -1,34 +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.functional;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-@Singleton
-@Component
-interface SingletonGenericComponent {
-
- ScopedGeneric<A> scopedGenericA();
-
- ScopedGeneric<B> scopedGenericB();
-
- ScopedSimpleGeneric<A> scopedSimpleGenericA();
-
- ScopedSimpleGeneric<B> scopedSimpleGenericB();
-
-}
diff --git a/javatests/dagger/functional/SomeQualifier.java b/javatests/dagger/functional/SomeQualifier.java
deleted file mode 100644
index 126398c..0000000
--- a/javatests/dagger/functional/SomeQualifier.java
+++ /dev/null
@@ -1,28 +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.functional;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-@Documented
-@Retention(RUNTIME)
-@Qualifier
-public @interface SomeQualifier {}
diff --git a/javatests/dagger/functional/Thing.java b/javatests/dagger/functional/Thing.java
deleted file mode 100644
index b51b96a..0000000
--- a/javatests/dagger/functional/Thing.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import dagger.functional.sub.OtherThing;
-import javax.inject.Inject;
-
-final class Thing {
- @Inject Thing(@SuppressWarnings("unused") OtherThing unused) {}
-}
diff --git a/javatests/dagger/functional/TypeWithInheritedMembersInjection.java b/javatests/dagger/functional/TypeWithInheritedMembersInjection.java
deleted file mode 100644
index b74f348..0000000
--- a/javatests/dagger/functional/TypeWithInheritedMembersInjection.java
+++ /dev/null
@@ -1,24 +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.functional;
-
-import javax.inject.Inject;
-
-final class TypeWithInheritedMembersInjection extends AbstractMiddleClassWithoutMembers {
- @Inject TypeWithInheritedMembersInjection() {}
-}
-
diff --git a/javatests/dagger/functional/UnwrappedAnnotationKey.java b/javatests/dagger/functional/UnwrappedAnnotationKey.java
deleted file mode 100644
index e9298f2..0000000
--- a/javatests/dagger/functional/UnwrappedAnnotationKey.java
+++ /dev/null
@@ -1,25 +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.functional;
-
-import dagger.MapKey;
-import dagger.multibindings.StringKey;
-
-@MapKey(unwrapValue = true)
-@interface UnwrappedAnnotationKey {
- StringKey value();
-}
diff --git a/javatests/dagger/functional/WrappedAnnotationKey.java b/javatests/dagger/functional/WrappedAnnotationKey.java
deleted file mode 100644
index 0256111..0000000
--- a/javatests/dagger/functional/WrappedAnnotationKey.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.functional;
-
-import dagger.MapKey;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.StringKey;
-
-@MapKey(unwrapValue = false)
-@interface WrappedAnnotationKey {
- StringKey value();
- int[] integers();
- ClassKey[] annotations();
- Class<? extends Number>[] classes();
-}
diff --git a/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java b/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java
deleted file mode 100644
index 20a89d4..0000000
--- a/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java
+++ /dev/null
@@ -1,40 +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.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
deleted file mode 100644
index ae6b3a4..0000000
--- a/javatests/dagger/functional/aot/MapFrameworkInstanceWithContributionsInMultipleImplementationsTest.java
+++ /dev/null
@@ -1,94 +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.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
deleted file mode 100644
index 1813ad2..0000000
--- a/javatests/dagger/functional/aot/MissingBindingReplacedWithGeneratedInstance.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.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
deleted file mode 100644
index 7084f83..0000000
--- a/javatests/dagger/functional/aot/ModifiedFrameworkInstancesTest.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.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
deleted file mode 100644
index 853e22b..0000000
--- a/javatests/dagger/functional/aot/PrunedBindingDependedOnInSuperInitializationTest.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.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
deleted file mode 100644
index f995789..0000000
--- a/javatests/dagger/functional/aot/PrunedFrameworkInstanceWithModuleInstanceTest.java
+++ /dev/null
@@ -1,83 +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.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
deleted file mode 100644
index 2723ac0..0000000
--- a/javatests/dagger/functional/aot/ScopedBindsWithMissingDependency.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.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
deleted file mode 100644
index 689689c..0000000
--- a/javatests/dagger/functional/aot/SubcomponentWithInaccessibleMissingBindingMethod.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.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
deleted file mode 100644
index 06cebb9..0000000
--- a/javatests/dagger/functional/aot/SubcomponentWithModifiedInaccessibleDependency.java
+++ /dev/null
@@ -1,32 +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.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
deleted file mode 100644
index 2eee3c9..0000000
--- a/javatests/dagger/functional/aot/sub/BindsPackagePrivateModule.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.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
deleted file mode 100644
index c629f6e..0000000
--- a/javatests/dagger/functional/aot/sub/PackagePrivate.java
+++ /dev/null
@@ -1,19 +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.functional.aot.sub;
-
-final class PackagePrivate {}
diff --git a/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java b/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java
deleted file mode 100644
index b5ced6f..0000000
--- a/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java
+++ /dev/null
@@ -1,24 +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.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
deleted file mode 100644
index 1d69723..0000000
--- a/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateOptionalDep.java
+++ /dev/null
@@ -1,25 +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.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
deleted file mode 100644
index d908b1c..0000000
--- a/javatests/dagger/functional/aot/sub/SubcomponentWithInaccessibleOptionalBindingMethod.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.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/binds/AccessesExposedComponent.java b/javatests/dagger/functional/binds/AccessesExposedComponent.java
deleted file mode 100644
index 61952b6..0000000
--- a/javatests/dagger/functional/binds/AccessesExposedComponent.java
+++ /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.
- */
-
-package dagger.functional.binds;
-
-import dagger.Component;
-import dagger.functional.binds.subpackage.Exposed;
-import dagger.functional.binds.subpackage.ExposedModule;
-import dagger.functional.binds.subpackage.UsesExposedInjectsMembers;
-import java.util.List;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-/**
- * This component tests cases where the right-hand-side of a {@link dagger.Binds} method is not
- * accessible from the component, but the left-hand-side is. If the right-hand-side is represented
- * as a Provider (e.g. because it is scoped), then the raw {@code Provider.get()} will return {@link
- * Object}, which must be downcasted to the type accessible from the component. See {@code
- * instanceRequiresCast()} in {@link dagger.internal.codegen.DelegateBindingExpression}.
- */
-@Singleton
-@Component(modules = ExposedModule.class)
-interface AccessesExposedComponent {
- Exposed exposed();
- Provider<Exposed> exposedProvider();
-
- List<? extends Exposed> listOfExposed();
- Provider<List<? extends Exposed>> providerOfListOfExposed();
-
- UsesExposedInjectsMembers usesExposedInjectsMembers();
-
- /**
- * This provider needs a {@code Provider<ExposedInjectsMembers>}, which is bound to a {@code
- * Provider<NotExposedInjectsMembers>}. This method is here to make sure that the cast happens
- * appropriately.
- */
- Provider<UsesExposedInjectsMembers> usesExposedInjectsMembersProvider();
-}
diff --git a/javatests/dagger/functional/binds/BindsCollectionsWithoutMultibindingsTest.java b/javatests/dagger/functional/binds/BindsCollectionsWithoutMultibindingsTest.java
deleted file mode 100644
index 90b1bbc..0000000
--- a/javatests/dagger/functional/binds/BindsCollectionsWithoutMultibindingsTest.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.functional.binds;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class BindsCollectionsWithoutMultibindingsTest {
- @Module
- abstract static class M {
- @Provides
- static HashSet<String> provideHashSet() {
- HashSet<String> set = new HashSet<>();
- set.add("binds");
- set.add("set");
- return set;
- }
-
- @Binds
- abstract Set<String> bindStringSet(HashSet<String> set);
-
- @Provides
- static HashMap<String, String> provideHashMap() {
- HashMap<String, String> map = new HashMap<>();
- map.put("binds", "map");
- map.put("without", "multibindings");
- return map;
- }
-
- @Binds
- abstract Map<String, String> bindStringMap(HashMap<String, String> map);
- }
-
- @Component(modules = M.class)
- interface C {
- Set<String> set();
-
- Map<String, String> map();
- }
-
- @Test
- public void works() {
- C component = DaggerBindsCollectionsWithoutMultibindingsTest_C.create();
-
- assertThat(component.set()).containsExactly("binds", "set");
- assertThat(component.map())
- .containsExactly(
- "binds", "map",
- "without", "multibindings");
- }
-}
diff --git a/javatests/dagger/functional/binds/BindsTest.java b/javatests/dagger/functional/binds/BindsTest.java
deleted file mode 100644
index 999c303..0000000
--- a/javatests/dagger/functional/binds/BindsTest.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.functional.binds;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class BindsTest {
-
- private TestComponent component;
-
- @Before
- public void setUp() {
- component = DaggerTestComponent.create();
- }
-
- @Test
- public void bindDelegates() {
- assertThat(component.object()).isInstanceOf(FooOfStrings.class);
- assertThat(component.fooOfStrings()).isInstanceOf(FooOfStrings.class);
- assertThat(component.fooOfObjects()).isInstanceOf(FooOfObjects.class);
- assertThat(component.fooOfIntegers()).isNotNull();
- }
-
- @Test
- public void bindWithScope() {
- assertThat(component.qualifiedFooOfStrings())
- .isSameInstanceAs(component.qualifiedFooOfStrings());
- }
-
- @Test
- public void multibindings() {
- assertThat(component.foosOfNumbers()).hasSize(2);
- assertThat(component.objects()).hasSize(3);
- assertThat(component.charSequences()).hasSize(5);
-
- assertThat(component.integerObjectMap())
- .containsExactly(123, "123-string", 456, "456-string", 789, "789-string");
- assertThat(component.integerProviderOfObjectMap()).hasSize(3);
- assertThat(component.integerProviderOfObjectMap().get(123).get()).isEqualTo("123-string");
- assertThat(component.integerProviderOfObjectMap().get(456).get()).isEqualTo("456-string");
- assertThat(component.integerProviderOfObjectMap().get(789).get()).isEqualTo("789-string");
-
- assertThat(component.qualifiedIntegerObjectMap()).hasSize(1);
-
- assertThat(component.primitiveSet()).containsExactly(100);
- assertThat(component.primitiveValueMap()).containsExactly(10, 100);
- }
-}
diff --git a/javatests/dagger/functional/binds/Foo.java b/javatests/dagger/functional/binds/Foo.java
deleted file mode 100644
index 12b0e4e..0000000
--- a/javatests/dagger/functional/binds/Foo.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.
- */
-
-package dagger.functional.binds;
-
-/**
- * This is the type that will be bound. We throw in generics just to complicate the test.
- */
-interface Foo<T> {}
diff --git a/javatests/dagger/functional/binds/FooOfObjects.java b/javatests/dagger/functional/binds/FooOfObjects.java
deleted file mode 100644
index c50f2fa..0000000
--- a/javatests/dagger/functional/binds/FooOfObjects.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.functional.binds;
-
-import javax.inject.Inject;
-
-final class FooOfObjects implements Foo<Object> {
- @Inject FooOfObjects() {}
-}
diff --git a/javatests/dagger/functional/binds/FooOfStrings.java b/javatests/dagger/functional/binds/FooOfStrings.java
deleted file mode 100644
index 42fc704..0000000
--- a/javatests/dagger/functional/binds/FooOfStrings.java
+++ /dev/null
@@ -1,24 +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.functional.binds;
-
-import javax.inject.Inject;
-
-final class FooOfStrings implements Foo<String> {
- @Inject
- FooOfStrings() {}
-}
diff --git a/javatests/dagger/functional/binds/InterfaceModule.java b/javatests/dagger/functional/binds/InterfaceModule.java
deleted file mode 100644
index e9d36c0..0000000
--- a/javatests/dagger/functional/binds/InterfaceModule.java
+++ /dev/null
@@ -1,25 +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.functional.binds;
-
-import dagger.Binds;
-import dagger.Module;
-
-@Module
-interface InterfaceModule {
- @Binds Foo<Object> bindFooOfObjects(FooOfObjects impl);
-}
diff --git a/javatests/dagger/functional/binds/SimpleBindingModule.java b/javatests/dagger/functional/binds/SimpleBindingModule.java
deleted file mode 100644
index e1d5227..0000000
--- a/javatests/dagger/functional/binds/SimpleBindingModule.java
+++ /dev/null
@@ -1,162 +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.functional.binds;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Reusable;
-import dagger.functional.SomeQualifier;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.TreeSet;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-@Module(includes = InterfaceModule.class)
-abstract class SimpleBindingModule {
- @Binds
- abstract Object bindObject(FooOfStrings impl);
-
- @Binds
- @Reusable
- @SomeQualifier
- abstract Object bindReusableObject(FooOfStrings impl);
-
- @Binds
- abstract Foo<String> bindFooOfStrings(FooOfStrings impl);
-
- @Binds
- abstract Foo<? extends Number> bindFooOfNumbers(Foo<Integer> fooOfIntegers);
-
- @Binds
- @Singleton
- @SomeQualifier
- abstract Foo<String> bindQualifiedFooOfStrings(FooOfStrings impl);
-
- @Provides
- static Foo<Integer> provideFooOfIntegers() {
- return new Foo<Integer>() {};
- }
-
- @Provides
- static Foo<Double> provideFooOfDoubles() {
- return new Foo<Double>() {};
- }
-
- @Binds
- @IntoSet
- abstract Foo<? extends Number> bindFooOfIntegersIntoSet(Foo<Integer> fooOfIntegers);
-
- @Binds
- @IntoSet
- abstract Foo<? extends Number> bindFooExtendsNumberIntoSet(Foo<Double> fooOfDoubles);
-
- @Binds
- @ElementsIntoSet
- abstract Set<Object> bindSetOfFooNumbersToObjects(Set<Foo<? extends Number>> setOfFooNumbers);
-
- @Binds
- @IntoSet
- abstract Object bindFooOfStringsIntoSetOfObjects(FooOfStrings impl);
-
- @Provides
- static HashSet<String> provideStringHashSet() {
- return new HashSet<>(Arrays.asList("hash-string1", "hash-string2"));
- }
-
- @Provides
- static TreeSet<CharSequence> provideCharSequenceTreeSet() {
- return new TreeSet<CharSequence>(Arrays.asList("tree-charSequence1", "tree-charSequence2"));
- }
-
- @Provides
- static Collection<CharSequence> provideCharSequenceCollection() {
- return Arrays.<CharSequence>asList("list-charSequence");
- }
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindHashSetOfStrings(HashSet<String> set);
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindTreeSetOfCharSequences(TreeSet<CharSequence> set);
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindCollectionOfCharSequences(Collection<CharSequence> collection);
-
- @Binds
- @IntoMap
- @IntKey(123)
- abstract Object bind123ForMap(@Named("For-123") String string);
-
- @Binds
- @IntoMap
- @IntKey(456)
- abstract Object bind456ForMap(@Named("For-456") String string);
-
- @Provides
- @IntoMap
- @IntKey(789)
- static Object provide789ForMap() {
- return "789-string";
- }
-
- @Binds
- @SomeQualifier
- abstract int primitiveToPrimitive(int intValue);
-
- @Binds
- @IntoSet
- abstract int intValueIntoSet(int intValue);
-
- @Binds
- @IntoMap
- @IntKey(10)
- abstract int intValueIntoMap(int intValue);
-
- @Provides
- static int intValue() {
- return 100;
- }
-
- @Binds
- @IntoMap
- @IntKey(123)
- @SomeQualifier
- abstract Object bindFooOfStringsIntoQualifiedMap(FooOfStrings fooOfStrings);
-
- @Provides
- @Named("For-123")
- static String provide123String() {
- return "123-string";
- }
-
- @Provides
- @Named("For-456")
- static String provide456String() {
- return "456-string";
- }
-}
diff --git a/javatests/dagger/functional/binds/TestComponent.java b/javatests/dagger/functional/binds/TestComponent.java
deleted file mode 100644
index 3299dc8..0000000
--- a/javatests/dagger/functional/binds/TestComponent.java
+++ /dev/null
@@ -1,60 +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.functional.binds;
-
-import dagger.Component;
-import dagger.functional.SomeQualifier;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-@Singleton
-@Component(modules = SimpleBindingModule.class)
-public interface TestComponent {
- Object object();
-
- @SomeQualifier
- Object reusableObject();
-
- Foo<String> fooOfStrings();
-
- Foo<Object> fooOfObjects();
-
- @SomeQualifier
- Foo<String> qualifiedFooOfStrings();
-
- Foo<Integer> fooOfIntegers();
-
- Set<Foo<? extends Number>> foosOfNumbers();
-
- Set<Object> objects();
-
- Set<CharSequence> charSequences();
-
- Map<Integer, Object> integerObjectMap();
-
- Map<Integer, Provider<Object>> integerProviderOfObjectMap();
-
- @SomeQualifier Map<Integer, Object> qualifiedIntegerObjectMap();
-
- @SomeQualifier int uniquePrimitive();
-
- Set<Integer> primitiveSet();
-
- Map<Integer, Integer> primitiveValueMap();
-}
diff --git a/javatests/dagger/functional/binds/subpackage/Exposed.java b/javatests/dagger/functional/binds/subpackage/Exposed.java
deleted file mode 100644
index 885aee4..0000000
--- a/javatests/dagger/functional/binds/subpackage/Exposed.java
+++ /dev/null
@@ -1,19 +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.functional.binds.subpackage;
-
-public interface Exposed {}
\ No newline at end of file
diff --git a/javatests/dagger/functional/binds/subpackage/ExposedInjectsMembers.java b/javatests/dagger/functional/binds/subpackage/ExposedInjectsMembers.java
deleted file mode 100644
index 074289c..0000000
--- a/javatests/dagger/functional/binds/subpackage/ExposedInjectsMembers.java
+++ /dev/null
@@ -1,19 +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.functional.binds.subpackage;
-
-public interface ExposedInjectsMembers {}
diff --git a/javatests/dagger/functional/binds/subpackage/ExposedModule.java b/javatests/dagger/functional/binds/subpackage/ExposedModule.java
deleted file mode 100644
index a2660d9..0000000
--- a/javatests/dagger/functional/binds/subpackage/ExposedModule.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.functional.binds.subpackage;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import java.util.ArrayList;
-import java.util.List;
-import javax.inject.Singleton;
-
-@Module
-public abstract class ExposedModule {
- @Binds
- abstract Exposed notExposed(NotExposed notExposed);
-
- @Provides
- @Singleton // force a rawtypes Provider
- static List<NotExposed> notExposedList() {
- return new ArrayList<>();
- }
-
- @Binds
- abstract List<? extends Exposed> bindList(List<NotExposed> notExposedList);
-
- @Binds
- abstract ExposedInjectsMembers bindExposedInjectsMembers(
- NotExposedInjectsMembers notExposedInjectsMembers);
-}
diff --git a/javatests/dagger/functional/binds/subpackage/NotExposed.java b/javatests/dagger/functional/binds/subpackage/NotExposed.java
deleted file mode 100644
index a8774ee..0000000
--- a/javatests/dagger/functional/binds/subpackage/NotExposed.java
+++ /dev/null
@@ -1,26 +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.functional.binds.subpackage;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton // force a Provider, which will not have a type parameter since this is not public
-class NotExposed implements Exposed {
- @Inject
- NotExposed() {}
-}
\ No newline at end of file
diff --git a/javatests/dagger/functional/binds/subpackage/NotExposedInjectsMembers.java b/javatests/dagger/functional/binds/subpackage/NotExposedInjectsMembers.java
deleted file mode 100644
index 1f6a1b7..0000000
--- a/javatests/dagger/functional/binds/subpackage/NotExposedInjectsMembers.java
+++ /dev/null
@@ -1,25 +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.functional.binds.subpackage;
-
-import javax.inject.Inject;
-
-final class NotExposedInjectsMembers implements ExposedInjectsMembers {
- @Inject Exposed exposed;
-
- @Inject NotExposedInjectsMembers() {}
-}
diff --git a/javatests/dagger/functional/binds/subpackage/UsesExposedInjectsMembers.java b/javatests/dagger/functional/binds/subpackage/UsesExposedInjectsMembers.java
deleted file mode 100644
index 3ee2e8f..0000000
--- a/javatests/dagger/functional/binds/subpackage/UsesExposedInjectsMembers.java
+++ /dev/null
@@ -1,25 +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.functional.binds.subpackage;
-
-import javax.inject.Inject;
-
-public class UsesExposedInjectsMembers {
- @Inject ExposedInjectsMembers exposedInjectsMembers;
-
- @Inject UsesExposedInjectsMembers(ExposedInjectsMembers exposedInjectsMembers) {}
-}
diff --git a/javatests/dagger/functional/builder/BuildMethodCovariantReturn.java b/javatests/dagger/functional/builder/BuildMethodCovariantReturn.java
deleted file mode 100644
index b55981f..0000000
--- a/javatests/dagger/functional/builder/BuildMethodCovariantReturn.java
+++ /dev/null
@@ -1,28 +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.functional.builder;
-
-import dagger.Component;
-
-@Component
-interface BuildMethodCovariantReturn {
-
- @Component.Builder
- interface Builder {
- Object build();
- }
-}
diff --git a/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java b/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java
deleted file mode 100644
index 07ebbc8..0000000
--- a/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.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.functional.builder;
-
-import dagger.Component;
-
-interface BuildMethodCovariantReturnInherited {
- @Component
- interface Simple {
- interface BuilderSupertype {
- Object build();
- }
-
- @Component.Builder
- interface Builder extends BuilderSupertype {}
- }
-
- interface ComponentSupertype {}
-
- @Component
- interface GenericBuilderType extends ComponentSupertype {
- interface GenericBuilderSupertype<T> {
- T build();
- }
-
- @Component.Builder
- interface Builder extends GenericBuilderSupertype<ComponentSupertype> {}
- }
-
- interface ParameterizedComponentSupertype<T> {}
-
- @Component
- interface GenericComponentSupertypeAndBuilderSupertype
- extends ParameterizedComponentSupertype<Object> {
-
- interface GenericBuilderSupertype<T> {
- ParameterizedComponentSupertype<T> build();
- }
-
- @Component.Builder
- interface Builder extends GenericBuilderSupertype<Object> {}
- }
-}
diff --git a/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java b/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java
deleted file mode 100644
index 33d3816..0000000
--- a/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.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.functional.builder;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.BindsInstance;
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests that {@code @BindsInstance} works when applied to the parameter of a builder's setter
- * method.
- */
-@RunWith(JUnit4.class)
-public final class BuilderBindsInstanceParameterTest {
-
- @Component
- interface TestComponent {
- String s();
-
- int i();
-
- @Component.Builder
- interface Builder {
- // https://github.com/google/dagger/issues/1464
- Builder s(@BindsInstance String notTheSameNameAsMethod);
-
- Builder i(@BindsInstance int i);
-
- TestComponent build();
- }
- }
-
- @Test
- public void builder_bindsInstanceOnParameter_allowed() {
- TestComponent component = DaggerBuilderBindsInstanceParameterTest_TestComponent.builder()
- .s("hello")
- .i(42)
- .build();
- assertThat(component.s()).isEqualTo("hello");
- assertThat(component.i()).isEqualTo(42);
- }
-}
diff --git a/javatests/dagger/functional/builder/BuilderTest.java b/javatests/dagger/functional/builder/BuilderTest.java
deleted file mode 100644
index 75b15c4..0000000
--- a/javatests/dagger/functional/builder/BuilderTest.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.functional.builder;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class BuilderTest {
-
- @Test public void interfaceBuilder() {
- TestComponentWithBuilderInterface.Builder builder =
- DaggerTestComponentWithBuilderInterface.builder();
-
- // Make sure things fail if we don't set our required modules.
- try {
- builder.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
- .stringModule(new StringModule("sam"))
- .depComponent(new DepComponent() {});
- builder.doubleModule(new DoubleModule());
- // Don't set other modules -- make sure it works.
-
- TestComponentWithBuilderInterface component = builder.build();
- assertThat(component.s()).isEqualTo("sam");
- assertThat(component.i()).isEqualTo(1);
- assertThat(component.d()).isEqualTo(4.2d);
- assertThat(component.f()).isEqualTo(5.5f);
- assertThat(component.l()).isEqualTo(6L);
- }
-
- @Test public void abstractClassBuilder() {
- TestComponentWithBuilderAbstractClass.Builder builder =
- TestComponentWithBuilderAbstractClass.builder();
-
- // Make sure things fail if we don't set our required modules.
- try {
- builder.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder.intModule(new IntModuleIncludingDoubleAndFloat(1))
- .stringModule(new StringModule("sam"))
- .depComponent(new DepComponent() {});
- builder.doubleModule(new DoubleModule());
- // Don't set other modules -- make sure it works.
-
- TestComponentWithBuilderAbstractClass component = builder.build();
- assertThat(component.s()).isEqualTo("sam");
- assertThat(component.i()).isEqualTo(1);
- assertThat(component.d()).isEqualTo(4.2d);
- assertThat(component.f()).isEqualTo(5.5f);
- assertThat(component.l()).isEqualTo(6L);
- }
-
- @Test public void interfaceGenericBuilder() {
- TestComponentWithGenericBuilderInterface.Builder builder =
- DaggerTestComponentWithGenericBuilderInterface.builder();
-
- // Make sure things fail if we don't set our required modules.
- try {
- builder.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
- .setM1(new StringModule("sam"))
- .depComponent(new DepComponent() {});
- builder.doubleModule(new DoubleModule());
- // Don't set other modules -- make sure it works.
-
- TestComponentWithGenericBuilderInterface component = builder.build();
- assertThat(component.s()).isEqualTo("sam");
- assertThat(component.i()).isEqualTo(1);
- assertThat(component.d()).isEqualTo(4.2d);
- assertThat(component.f()).isEqualTo(5.5f);
- assertThat(component.l()).isEqualTo(6L);
- }
-
- @Test public void abstractClassGenericBuilder() {
- TestComponentWithGenericBuilderAbstractClass.Builder builder =
- DaggerTestComponentWithGenericBuilderAbstractClass.builder();
-
- // Make sure things fail if we don't set our required modules.
- try {
- builder.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder.setM2(new IntModuleIncludingDoubleAndFloat(1))
- .setM1(new StringModule("sam"))
- .depComponent(new DepComponent() {});
- builder.doubleModule(new DoubleModule());
- // Don't set other modules -- make sure it works.
-
- TestComponentWithGenericBuilderAbstractClass component = builder.build();
- assertThat(component.s()).isEqualTo("sam");
- assertThat(component.i()).isEqualTo(1);
- assertThat(component.d()).isEqualTo(4.2d);
- assertThat(component.f()).isEqualTo(5.5f);
- assertThat(component.l()).isEqualTo(6L);
- }
-
- @Test public void subcomponents_interface() {
- ParentComponent parent = DaggerParentComponent.create();
- TestChildComponentWithBuilderInterface.Builder builder1 = parent.childInterfaceBuilder();
- try {
- builder1.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder1.setM2(new IntModuleIncludingDoubleAndFloat(1))
- .setM1(new StringModule("sam"))
- .set(new ByteModule((byte)7));
- builder1.set(new FloatModule());
- TestChildComponentWithBuilderInterface child1 = builder1.build();
- assertThat(child1.s()).isEqualTo("sam");
- assertThat(child1.i()).isEqualTo(1);
- assertThat(child1.d()).isEqualTo(4.2d);
- assertThat(child1.f()).isEqualTo(5.5f);
- assertThat(child1.l()).isEqualTo(6L);
- assertThat(child1.b()).isEqualTo((byte)7);
- }
-
- @Test public void subcomponents_abstractclass() {
- ParentComponent parent = DaggerParentComponent.create();
- TestChildComponentWithBuilderAbstractClass.Builder builder2 =
- parent.childAbstractClassBuilder();
- try {
- builder2.build();
- fail();
- } catch(IllegalStateException expected) {}
-
- builder2.setM2(new IntModuleIncludingDoubleAndFloat(10))
- .setM1(new StringModule("tara"))
- .set(new ByteModule((byte)70));
- builder2.set(new FloatModule());
- TestChildComponentWithBuilderAbstractClass child2 = builder2.build();
- assertThat(child2.s()).isEqualTo("tara");
- assertThat(child2.i()).isEqualTo(10);
- assertThat(child2.d()).isEqualTo(4.2d);
- assertThat(child2.f()).isEqualTo(5.5f);
- assertThat(child2.l()).isEqualTo(6L);
- assertThat(child2.b()).isEqualTo((byte)70);
- }
-
- @Test
- public void grandchildren() {
- ParentComponent parent = DaggerParentComponent.create();
- MiddleChild middle1 = parent.middleBuilder().set(new StringModule("sam")).build();
- Grandchild grandchild1 =
- middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
- Grandchild grandchild2 =
- middle1.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
-
- assertThat(middle1.s()).isEqualTo("sam");
- assertThat(grandchild1.i()).isEqualTo(21);
- assertThat(grandchild1.s()).isEqualTo("sam");
- assertThat(grandchild2.i()).isEqualTo(22);
- assertThat(grandchild2.s()).isEqualTo("sam");
-
- // Make sure grandchildren from newer children have no relation to the older ones.
- MiddleChild middle2 = parent.middleBuilder().set(new StringModule("tara")).build();
- Grandchild grandchild3 =
- middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(23)).build();
- Grandchild grandchild4 =
- middle2.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(24)).build();
-
- assertThat(middle2.s()).isEqualTo("tara");
- assertThat(grandchild3.i()).isEqualTo(23);
- assertThat(grandchild3.s()).isEqualTo("tara");
- assertThat(grandchild4.i()).isEqualTo(24);
- assertThat(grandchild4.s()).isEqualTo("tara");
- }
-
- @Test
- public void diamondGrandchildren() {
- ParentComponent parent = DaggerParentComponent.create();
- MiddleChild middle = parent.middleBuilder().set(new StringModule("sam")).build();
- OtherMiddleChild other = parent.otherBuilder().set(new StringModule("tara")).build();
-
- Grandchild middlegrand =
- middle.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(21)).build();
- Grandchild othergrand =
- other.grandchildBuilder().set(new IntModuleIncludingDoubleAndFloat(22)).build();
-
- assertThat(middle.s()).isEqualTo("sam");
- assertThat(other.s()).isEqualTo("tara");
- assertThat(middlegrand.s()).isEqualTo("sam");
- assertThat(othergrand.s()).isEqualTo("tara");
- assertThat(middlegrand.i()).isEqualTo(21);
- assertThat(othergrand.i()).isEqualTo(22);
- }
-
- @Test
- public void genericSubcomponentMethod() {
- ParentOfGenericComponent parent =
- DaggerParentOfGenericComponent.builder().stringModule(new StringModule("sam")).build();
- Grandchild.Builder builder = parent.subcomponentBuilder();
- Grandchild child = builder.set(new IntModuleIncludingDoubleAndFloat(21)).build();
- assertThat(child.s()).isEqualTo("sam");
- assertThat(child.i()).isEqualTo(21);
- }
-
- @Test
- public void requireSubcomponentBuilderProviders() {
- ParentComponent parent = DaggerParentComponent.create();
- MiddleChild middle =
- parent
- .requiresMiddleChildBuilder()
- .subcomponentBuilderProvider()
- .get()
- .set(new StringModule("sam"))
- .build();
- Grandchild grandchild =
- middle
- .requiresGrandchildBuilder()
- .subcomponentBuilderProvider()
- .get()
- .set(new IntModuleIncludingDoubleAndFloat(12))
- .build();
- assertThat(middle.s()).isEqualTo("sam");
- assertThat(grandchild.i()).isEqualTo(12);
- assertThat(grandchild.s()).isEqualTo("sam");
- }
-
- @Test
- public void requireSubcomponentBuilders() {
- ParentComponent parent = DaggerParentComponent.create();
- MiddleChild middle =
- parent
- .requiresMiddleChildBuilder()
- .subcomponentBuilder()
- .set(new StringModule("sam"))
- .build();
- Grandchild grandchild =
- middle
- .requiresGrandchildBuilder()
- .subcomponentBuilder()
- .set(new IntModuleIncludingDoubleAndFloat(12))
- .build();
- assertThat(middle.s()).isEqualTo("sam");
- assertThat(grandchild.i()).isEqualTo(12);
- assertThat(grandchild.s()).isEqualTo("sam");
- }
-}
diff --git a/javatests/dagger/functional/builder/ByteModule.java b/javatests/dagger/functional/builder/ByteModule.java
deleted file mode 100644
index 4b6602f..0000000
--- a/javatests/dagger/functional/builder/ByteModule.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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class ByteModule {
- final byte b;
-
- ByteModule(byte b) {
- this.b = b;
- }
-
- @Provides byte b() { return b; }
-}
diff --git a/javatests/dagger/functional/builder/DepComponent.java b/javatests/dagger/functional/builder/DepComponent.java
deleted file mode 100644
index 6e85c7a..0000000
--- a/javatests/dagger/functional/builder/DepComponent.java
+++ /dev/null
@@ -1,23 +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.functional.builder;
-
-import dagger.Component;
-
-@Component
-interface DepComponent {
-}
diff --git a/javatests/dagger/functional/builder/DoubleModule.java b/javatests/dagger/functional/builder/DoubleModule.java
deleted file mode 100644
index d1be37c..0000000
--- a/javatests/dagger/functional/builder/DoubleModule.java
+++ /dev/null
@@ -1,28 +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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class DoubleModule {
- @Provides
- double d() {
- return 4.2d;
- }
-}
diff --git a/javatests/dagger/functional/builder/FloatModule.java b/javatests/dagger/functional/builder/FloatModule.java
deleted file mode 100644
index d9990c0..0000000
--- a/javatests/dagger/functional/builder/FloatModule.java
+++ /dev/null
@@ -1,28 +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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class FloatModule {
- @Provides
- float f() {
- return 5.5f;
- }
-}
diff --git a/javatests/dagger/functional/builder/GenericParent.java b/javatests/dagger/functional/builder/GenericParent.java
deleted file mode 100644
index 9563103..0000000
--- a/javatests/dagger/functional/builder/GenericParent.java
+++ /dev/null
@@ -1,21 +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.functional.builder;
-
-interface GenericParent<B> {
- B subcomponentBuilder();
-}
diff --git a/javatests/dagger/functional/builder/Grandchild.java b/javatests/dagger/functional/builder/Grandchild.java
deleted file mode 100644
index 45fe213..0000000
--- a/javatests/dagger/functional/builder/Grandchild.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.functional.builder;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = IntModuleIncludingDoubleAndFloat.class)
-interface Grandchild {
- int i();
- String s();
-
- @Subcomponent.Builder
- interface Builder {
- Grandchild build();
- Builder set(IntModuleIncludingDoubleAndFloat intModule);
- }
-}
diff --git a/javatests/dagger/functional/builder/IntModuleIncludingDoubleAndFloat.java b/javatests/dagger/functional/builder/IntModuleIncludingDoubleAndFloat.java
deleted file mode 100644
index 37f5ad7..0000000
--- a/javatests/dagger/functional/builder/IntModuleIncludingDoubleAndFloat.java
+++ /dev/null
@@ -1,34 +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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module(includes = { DoubleModule.class, FloatModule.class })
-class IntModuleIncludingDoubleAndFloat {
- final int integer;
-
- IntModuleIncludingDoubleAndFloat(int integer) {
- this.integer = integer;
- }
-
- @Provides
- int integer() {
- return integer;
- }
-}
diff --git a/javatests/dagger/functional/builder/LongModule.java b/javatests/dagger/functional/builder/LongModule.java
deleted file mode 100644
index 7b777ec..0000000
--- a/javatests/dagger/functional/builder/LongModule.java
+++ /dev/null
@@ -1,28 +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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class LongModule {
- @Provides
- long l() {
- return 6L;
- }
-}
diff --git a/javatests/dagger/functional/builder/MiddleChild.java b/javatests/dagger/functional/builder/MiddleChild.java
deleted file mode 100644
index 762e2a0..0000000
--- a/javatests/dagger/functional/builder/MiddleChild.java
+++ /dev/null
@@ -1,35 +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.functional.builder;
-
-import dagger.Subcomponent;
-
-@MiddleScope
-@Subcomponent(modules = StringModule.class)
-interface MiddleChild {
- String s();
-
- Grandchild.Builder grandchildBuilder();
-
- RequiresSubcomponentBuilder<Grandchild.Builder> requiresGrandchildBuilder();
-
- @Subcomponent.Builder
- interface Builder {
- MiddleChild build();
- Builder set(StringModule stringModule);
- }
-}
diff --git a/javatests/dagger/functional/builder/MiddleScope.java b/javatests/dagger/functional/builder/MiddleScope.java
deleted file mode 100644
index ac63626..0000000
--- a/javatests/dagger/functional/builder/MiddleScope.java
+++ /dev/null
@@ -1,28 +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.functional.builder;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-@Scope
-@Retention(RUNTIME)
-@interface MiddleScope {
-
-}
diff --git a/javatests/dagger/functional/builder/OtherMiddleChild.java b/javatests/dagger/functional/builder/OtherMiddleChild.java
deleted file mode 100644
index 7ecc014..0000000
--- a/javatests/dagger/functional/builder/OtherMiddleChild.java
+++ /dev/null
@@ -1,34 +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.functional.builder;
-
-import dagger.Subcomponent;
-
-@MiddleScope
-@Subcomponent(modules = {StringModule.class, LongModule.class})
-interface OtherMiddleChild {
- long l();
- String s();
-
- Grandchild.Builder grandchildBuilder();
-
- @Subcomponent.Builder
- interface Builder {
- OtherMiddleChild build();
- Builder set(StringModule stringModule);
- }
-}
diff --git a/javatests/dagger/functional/builder/ParentComponent.java b/javatests/dagger/functional/builder/ParentComponent.java
deleted file mode 100644
index 425ba9a..0000000
--- a/javatests/dagger/functional/builder/ParentComponent.java
+++ /dev/null
@@ -1,32 +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.functional.builder;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-@Singleton
-@Component
-interface ParentComponent {
- TestChildComponentWithBuilderAbstractClass.Builder childAbstractClassBuilder();
- TestChildComponentWithBuilderInterface.Builder childInterfaceBuilder();
-
- MiddleChild.Builder middleBuilder();
- OtherMiddleChild.Builder otherBuilder();
-
- RequiresSubcomponentBuilder<MiddleChild.Builder> requiresMiddleChildBuilder();
-}
diff --git a/javatests/dagger/functional/builder/ParentOfGenericComponent.java b/javatests/dagger/functional/builder/ParentOfGenericComponent.java
deleted file mode 100644
index daeb7d9..0000000
--- a/javatests/dagger/functional/builder/ParentOfGenericComponent.java
+++ /dev/null
@@ -1,24 +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.functional.builder;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-@Component(modules = StringModule.class)
-@Singleton
-interface ParentOfGenericComponent extends GenericParent<Grandchild.Builder> {}
diff --git a/javatests/dagger/functional/builder/PrivateConstructors.java b/javatests/dagger/functional/builder/PrivateConstructors.java
deleted file mode 100644
index e5e9aa6..0000000
--- a/javatests/dagger/functional/builder/PrivateConstructors.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.functional.builder;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-
-final class PrivateConstructors {
- @Module
- static final class M {
- @Provides
- static String provideString() {
- return "str";
- }
-
- private M() {}
- }
-
- @Component(modules = M.class)
- interface C {
- String string();
-
- @Component.Builder
- interface Builder {
- // M should not be required, even though the constructor is inaccessible
- C build();
- }
- }
-}
diff --git a/javatests/dagger/functional/builder/RequiresSubcomponentBuilder.java b/javatests/dagger/functional/builder/RequiresSubcomponentBuilder.java
deleted file mode 100644
index a8dfa21..0000000
--- a/javatests/dagger/functional/builder/RequiresSubcomponentBuilder.java
+++ /dev/null
@@ -1,39 +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.functional.builder;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-class RequiresSubcomponentBuilder<B> {
- private final Provider<B> subcomponentBuilderProvider;
- private final B subcomponentBuilder;
-
- @Inject
- RequiresSubcomponentBuilder(Provider<B> subcomponentBuilderProvider, B subcomponentBuilder) {
- this.subcomponentBuilderProvider = subcomponentBuilderProvider;
- this.subcomponentBuilder = subcomponentBuilder;
- }
-
- Provider<B> subcomponentBuilderProvider() {
- return subcomponentBuilderProvider;
- }
-
- B subcomponentBuilder() {
- return subcomponentBuilder;
- }
-}
diff --git a/javatests/dagger/functional/builder/StringModule.java b/javatests/dagger/functional/builder/StringModule.java
deleted file mode 100644
index 9fbaa5b..0000000
--- a/javatests/dagger/functional/builder/StringModule.java
+++ /dev/null
@@ -1,34 +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.functional.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class StringModule {
- final String string;
-
- StringModule(String string) {
- this.string = string;
- }
-
- @Provides
- String string() {
- return string;
- }
-}
diff --git a/javatests/dagger/functional/builder/TestChildComponentWithBuilderAbstractClass.java b/javatests/dagger/functional/builder/TestChildComponentWithBuilderAbstractClass.java
deleted file mode 100644
index 1527a44..0000000
--- a/javatests/dagger/functional/builder/TestChildComponentWithBuilderAbstractClass.java
+++ /dev/null
@@ -1,48 +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.functional.builder;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
- LongModule.class, ByteModule.class})
-interface TestChildComponentWithBuilderAbstractClass {
- String s();
- int i();
- long l();
- float f();
- double d();
- byte b();
-
- abstract class SharedBuilder<B, C, M1, M2> {
- abstract C build(); // Test resolving return type of build()
- abstract B setM1(M1 m1); // Test resolving return type & param of setter
- abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
- abstract void setM3(DoubleModule doubleModule); // Test being overridden
- abstract SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test returning supertype.
- }
-
- @Subcomponent.Builder
- abstract class Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderAbstractClass,
- StringModule, IntModuleIncludingDoubleAndFloat> {
- @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariance
- @Override abstract void setM3(DoubleModule doubleModule); // Test simple overrides allowed
- abstract void set(ByteModule byteModule);
-
- // Note we're missing LongModule -- it's implicit
- }
-}
diff --git a/javatests/dagger/functional/builder/TestChildComponentWithBuilderInterface.java b/javatests/dagger/functional/builder/TestChildComponentWithBuilderInterface.java
deleted file mode 100644
index a02b1a1..0000000
--- a/javatests/dagger/functional/builder/TestChildComponentWithBuilderInterface.java
+++ /dev/null
@@ -1,48 +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.functional.builder;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class,
- LongModule.class, ByteModule.class})
-interface TestChildComponentWithBuilderInterface {
- String s();
- int i();
- long l();
- float f();
- double d();
- byte b();
-
- interface SharedBuilder<B, C, M1, M2> {
- C build(); // Test resolving return type of build()
- B setM1(M1 m1); // Test resolving return type & param of setter
- SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
- void setM3(DoubleModule doubleModule); // Test being overridden
- SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
- }
-
- @Subcomponent.Builder
- interface Builder extends SharedBuilder<Builder, TestChildComponentWithBuilderInterface,
- StringModule, IntModuleIncludingDoubleAndFloat> {
- @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
- @Override void setM3(DoubleModule doubleModule); // Test simple overrides allowed
- void set(ByteModule byteModule);
-
- // Note we're missing LongModule -- it's implicit
- }
-}
diff --git a/javatests/dagger/functional/builder/TestComponentWithBuilderAbstractClass.java b/javatests/dagger/functional/builder/TestComponentWithBuilderAbstractClass.java
deleted file mode 100644
index 636c8f4..0000000
--- a/javatests/dagger/functional/builder/TestComponentWithBuilderAbstractClass.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.functional.builder;
-
-import dagger.Component;
-
-@Component(
- modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
- dependencies = DepComponent.class)
-abstract class TestComponentWithBuilderAbstractClass {
-
- static Builder builder() {
- return DaggerTestComponentWithBuilderAbstractClass.builder();
- }
-
- abstract String s();
- abstract int i();
- abstract long l();
- abstract float f();
- abstract double d();
-
-
- static abstract class SharedBuilder {
- // Make sure we use the overriding signature.
- abstract Object build();
-
- Object stringModule(@SuppressWarnings("unused") StringModule stringModule) {
- return null;
- }
-
- SharedBuilder ignoredLongModule(@SuppressWarnings("unused") LongModule longModule) {
- return null;
- }
-
- }
-
- @Component.Builder
- static abstract class Builder extends SharedBuilder {
- @Override abstract TestComponentWithBuilderAbstractClass build(); // Narrowing return type
- @Override abstract Builder stringModule(StringModule stringModule); // Make abstract & narrow
- abstract Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
- abstract void doubleModule(DoubleModule doubleModule); // Module w/o args
- abstract void depComponent(DepComponent depComponent);
-
- Builder ignoredIntModule(
- @SuppressWarnings("unused") IntModuleIncludingDoubleAndFloat intModule) {
- return null;
- }
-
- // Note we're missing LongModule & FloatModule -- they/re implicit
- }
-}
diff --git a/javatests/dagger/functional/builder/TestComponentWithBuilderInterface.java b/javatests/dagger/functional/builder/TestComponentWithBuilderInterface.java
deleted file mode 100644
index ba55090..0000000
--- a/javatests/dagger/functional/builder/TestComponentWithBuilderInterface.java
+++ /dev/null
@@ -1,47 +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.functional.builder;
-
-import dagger.Component;
-
-@Component(
- modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
- dependencies = DepComponent.class)
-interface TestComponentWithBuilderInterface {
- String s();
- int i();
- long l();
- float f();
- double d();
-
- interface SharedBuilder {
- // Make sure we use the overriding signature.
- Object build();
- Object stringModule(StringModule m1);
- }
-
- @Component.Builder
- interface Builder extends SharedBuilder {
- @Override TestComponentWithBuilderInterface build(); // Narrowing return type
- @Override Builder stringModule(StringModule stringModule); // Narrowing return type
- Builder intModule(IntModuleIncludingDoubleAndFloat intModule);
- void doubleModule(DoubleModule doubleModule); // Module w/o args
- void depComponent(DepComponent depComponent);
-
- // Note we're missing LongModule & FloatModule -- they/re implicit
- }
-}
diff --git a/javatests/dagger/functional/builder/TestComponentWithGenericBuilderAbstractClass.java b/javatests/dagger/functional/builder/TestComponentWithGenericBuilderAbstractClass.java
deleted file mode 100644
index 5324957..0000000
--- a/javatests/dagger/functional/builder/TestComponentWithGenericBuilderAbstractClass.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.functional.builder;
-
-import dagger.Component;
-
-@Component(
- modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
- dependencies = DepComponent.class)
-interface TestComponentWithGenericBuilderAbstractClass {
- String s();
- int i();
- long l();
- float f();
- double d();
-
- static abstract class SharedBuilder<B, C, M1, M2> {
- abstract C build(); // Test resolving return type of build()
- abstract B setM1(M1 m1); // Test resolving return type & param of setter
- abstract SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
- abstract void doubleModule(DoubleModule doubleModule); // Test being overridden
- abstract SharedBuilder<B, C, M1, M2> depComponent(FloatModule floatModule); // Test return type
- }
-
- @Component.Builder
- static abstract class Builder extends SharedBuilder<Builder,
- TestComponentWithGenericBuilderAbstractClass, StringModule,
- IntModuleIncludingDoubleAndFloat> {
- @Override abstract Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides
- @Override abstract void doubleModule(DoubleModule module3); // Test simple overrides allowed
- abstract void depComponent(DepComponent depComponent);
-
- // Note we're missing LongModule & FloatModule -- they're implicit
- }
-}
diff --git a/javatests/dagger/functional/builder/TestComponentWithGenericBuilderInterface.java b/javatests/dagger/functional/builder/TestComponentWithGenericBuilderInterface.java
deleted file mode 100644
index 8e30c78..0000000
--- a/javatests/dagger/functional/builder/TestComponentWithGenericBuilderInterface.java
+++ /dev/null
@@ -1,48 +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.functional.builder;
-
-import dagger.Component;
-
-@Component(
- modules = {StringModule.class, IntModuleIncludingDoubleAndFloat.class, LongModule.class},
- dependencies = DepComponent.class)
-interface TestComponentWithGenericBuilderInterface {
- String s();
- int i();
- long l();
- float f();
- double d();
-
- interface SharedBuilder<B, C, M1, M2> {
- C build(); // Test resolving return type of build()
- B setM1(M1 m1); // Test resolving return type & param of setter
- SharedBuilder<B, C, M1, M2> setM2(M2 m2); // Test being overridden
- void doubleModule(DoubleModule doubleModule); // Test being overridden
- SharedBuilder<B, C, M1, M2> set(FloatModule floatModule); // Test return type is supertype.
- }
-
- @Component.Builder
- interface Builder extends SharedBuilder<Builder, TestComponentWithGenericBuilderInterface,
- StringModule, IntModuleIncludingDoubleAndFloat> {
- @Override Builder setM2(IntModuleIncludingDoubleAndFloat m2); // Test covariant overrides allowed
- @Override void doubleModule(DoubleModule module3); // Test simple overrides allowed
- void depComponent(DepComponent depComponent);
-
- // Note we're missing M5 -- that's implicit.
- }
-}
diff --git a/javatests/dagger/functional/builderbinds/BuilderBindsTest.java b/javatests/dagger/functional/builderbinds/BuilderBindsTest.java
deleted file mode 100644
index b5e5225..0000000
--- a/javatests/dagger/functional/builderbinds/BuilderBindsTest.java
+++ /dev/null
@@ -1,119 +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.functional.builderbinds;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.ImmutableList;
-import dagger.functional.builderbinds.TestComponent.Builder;
-import java.util.Arrays;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class BuilderBindsTest {
-
- @Test
- public void builderBinds() {
- TestComponent.Builder builder =
- DaggerTestComponent.builder()
- .count(5)
- .l(10L)
- .input("foo")
- .nullableInput("bar")
- .listOfString(Arrays.asList("x", "y", "z"));
- builder.boundInSubtype(20);
- TestComponent component = builder.build();
- assertThat(component.count()).isEqualTo(5);
- assertThat(component.input()).isEqualTo("foo");
- assertThat(component.nullableInput()).isEqualTo("bar");
- assertThat(component.listOfString()).containsExactly("x", "y", "z").inOrder();
- }
-
- @Test
- public void builderBindsNullableWithNull() {
- Builder builder =
- DaggerTestComponent.builder()
- .count(5)
- .l(10L)
- .input("foo")
- .nullableInput(null)
- .listOfString(ImmutableList.of());
- builder.boundInSubtype(20);
- TestComponent component = builder.build();
-
- assertThat(component.count()).isEqualTo(5);
- assertThat(component.input()).isEqualTo("foo");
- assertThat(component.nullableInput()).isNull();
- assertThat(component.listOfString()).isEmpty();
- }
-
- @Test
- public void builderBindsNonNullableWithNull() {
- try {
- DaggerTestComponent.builder().count(5).l(10L).input(null);
- fail("expected NullPointerException");
- } catch (NullPointerException expected) {
- }
- }
-
- @Test
- public void builderBindsPrimitiveNotSet() {
- try {
- TestComponent.Builder builder =
- DaggerTestComponent.builder()
- .l(10L)
- .input("foo")
- .nullableInput("bar")
- .listOfString(ImmutableList.of());
- builder.boundInSubtype(20);
- builder.build();
- fail("expected IllegalStateException");
- } catch (IllegalStateException expected) {
- }
- }
-
- @Test
- public void builderBindsNonNullableNotSet() {
- try {
- TestComponent.Builder builder =
- DaggerTestComponent.builder()
- .count(5)
- .l(10L)
- .nullableInput("foo")
- .listOfString(ImmutableList.of());
- builder.boundInSubtype(20);
- builder.build();
- fail("expected IllegalStateException");
- } catch (IllegalStateException expected) {
- }
- }
-
- @Test
- public void builderBindsNullableNotSet() {
- Builder builder =
- DaggerTestComponent.builder().count(5).l(10L).input("foo").listOfString(ImmutableList.of());
- builder.boundInSubtype(20);
- TestComponent component = builder.build();
- assertThat(component.count()).isEqualTo(5);
- assertThat(component.input()).isEqualTo("foo");
- assertThat(component.nullableInput()).isNull();
- assertThat(component.listOfString()).isEmpty();
- }
-}
diff --git a/javatests/dagger/functional/builderbinds/BuilderSupertype.java b/javatests/dagger/functional/builderbinds/BuilderSupertype.java
deleted file mode 100644
index 5828f9d..0000000
--- a/javatests/dagger/functional/builderbinds/BuilderSupertype.java
+++ /dev/null
@@ -1,25 +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.functional.builderbinds;
-
-import dagger.BindsInstance;
-import javax.inject.Named;
-
-interface BuilderSupertype {
- @BindsInstance
- void boundInSubtype(@Named("subtype") int subtype);
-}
diff --git a/javatests/dagger/functional/builderbinds/Nullable.java b/javatests/dagger/functional/builderbinds/Nullable.java
deleted file mode 100644
index 7924484..0000000
--- a/javatests/dagger/functional/builderbinds/Nullable.java
+++ /dev/null
@@ -1,19 +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.functional.builderbinds;
-
-@interface Nullable {}
diff --git a/javatests/dagger/functional/builderbinds/TestComponent.java b/javatests/dagger/functional/builderbinds/TestComponent.java
deleted file mode 100644
index 23a32b1..0000000
--- a/javatests/dagger/functional/builderbinds/TestComponent.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.functional.builderbinds;
-
-import dagger.BindsInstance;
-import dagger.Component;
-import java.util.List;
-import javax.inject.Named;
-
-@Component
-interface TestComponent {
- int count();
-
- long l();
-
- @Named("input")
- String input();
-
- @Nullable
- @Named("nullable input")
- String nullableInput();
-
- List<String> listOfString();
-
- @Named("subtype")
- int boundInSubtype();
-
- @Component.Builder
- interface Builder extends BuilderSupertype {
- @BindsInstance
- Builder count(int count);
-
- @BindsInstance
- Builder l(long l);
-
- @BindsInstance
- Builder input(@Named("input") String input);
-
- @BindsInstance
- Builder nullableInput(@Nullable @Named("nullable input") String nullableInput);
-
- @BindsInstance
- Builder listOfString(List<String> listOfString);
-
- TestComponent build();
- }
-}
diff --git a/javatests/dagger/functional/cycle/CycleTest.java b/javatests/dagger/functional/cycle/CycleTest.java
deleted file mode 100644
index d489bc6..0000000
--- a/javatests/dagger/functional/cycle/CycleTest.java
+++ /dev/null
@@ -1,103 +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.functional.cycle;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.cycle.Cycles.A;
-import dagger.functional.cycle.Cycles.BindsCycleComponent;
-import dagger.functional.cycle.Cycles.C;
-import dagger.functional.cycle.Cycles.ChildCycleComponent;
-import dagger.functional.cycle.Cycles.CycleComponent;
-import dagger.functional.cycle.Cycles.CycleMapComponent;
-import dagger.functional.cycle.Cycles.S;
-import dagger.functional.cycle.Cycles.SelfCycleComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class CycleTest {
- @Test
- public void providerIndirectionSelfCycle() {
- SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
- S s = selfCycleComponent.s();
- assertThat(s.sProvider.get()).isNotNull();
- }
-
- @Test
- public void providerIndirectionCycle() {
- CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
- A a = cycleComponent.a();
- C c = cycleComponent.c();
- assertThat(c.aProvider.get()).isNotNull();
- assertThat(a.b.c.aProvider.get()).isNotNull();
- assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
- }
-
- @Test
- public void lazyIndirectionSelfCycle() {
- SelfCycleComponent selfCycleComponent = DaggerCycles_SelfCycleComponent.create();
- S s = selfCycleComponent.s();
- assertThat(s.sLazy.get()).isNotNull();
- }
-
- @Test
- public void lazyIndirectionCycle() {
- CycleComponent cycleComponent = DaggerCycles_CycleComponent.create();
- A a = cycleComponent.a();
- C c = cycleComponent.c();
- assertThat(c.aLazy.get()).isNotNull();
- assertThat(a.b.c.aLazy.get()).isNotNull();
- assertThat(a.e.d.b.c.aLazy.get()).isNotNull();
- }
-
- @Test
- public void subcomponentIndirectionCycle() {
- ChildCycleComponent childCycleComponent = DaggerCycles_CycleComponent.create().child();
- A a = childCycleComponent.a();
- assertThat(a.b.c.aProvider.get()).isNotNull();
- assertThat(a.e.d.b.c.aProvider.get()).isNotNull();
- }
-
- @Test
- public void providerMapIndirectionCycle() {
- CycleMapComponent cycleMapComponent = DaggerCycles_CycleMapComponent.create();
- assertThat(cycleMapComponent.y()).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfX).containsKey("X");
- assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X")).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get()).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfX.get("X").get().y).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfX).hasSize(1);
- assertThat(cycleMapComponent.y().mapOfProvidersOfY).containsKey("Y");
- assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y")).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get()).isNotNull();
- assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfX).hasSize(1);
- assertThat(cycleMapComponent.y().mapOfProvidersOfY.get("Y").get().mapOfProvidersOfY).hasSize(1);
- assertThat(cycleMapComponent.y().mapOfProvidersOfY).hasSize(1);
- }
-
- /**
- * Tests that a cycle where a {@code @Binds} binding depends on a binding that has to be deferred
- * works.
- */
- @Test
- public void cycleWithDeferredBinds() {
- BindsCycleComponent bindsCycleComponent = DaggerCycles_BindsCycleComponent.create();
- assertThat(bindsCycleComponent.bar()).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/cycle/Cycles.java b/javatests/dagger/functional/cycle/Cycles.java
deleted file mode 100644
index f4faeab..0000000
--- a/javatests/dagger/functional/cycle/Cycles.java
+++ /dev/null
@@ -1,194 +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.functional.cycle;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-import java.util.Map;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Cycle classes used for testing cyclic dependencies.
- *
- * <pre>
- * {@literal A ← (E ← D ← B ← C ← Provider<A>, Lazy<A>), (B ← C ← Provider<A>, Lazy<A>)}
- * {@literal S ← Provider<S>, Lazy<S>}
- * </pre>
- */
-final class Cycles {
- private Cycles() {}
-
- static class A {
- public final B b;
- public final E e;
-
- @Inject
- A(E e, B b) {
- this.e = e;
- this.b = b;
- }
- }
-
- static class B {
- public final C c;
-
- @Inject
- B(C c) {
- this.c = c;
- }
- }
-
- static class C {
- public final Provider<A> aProvider;
- @Inject public Lazy<A> aLazy;
- @Inject public Provider<Lazy<A>> aLazyProvider;
-
- @Inject
- C(Provider<A> aProvider) {
- this.aProvider = aProvider;
- }
- }
-
- static class D {
- public final B b;
-
- @Inject
- D(B b) {
- this.b = b;
- }
- }
-
- static class E {
- public final D d;
-
- @Inject
- E(D d) {
- this.d = d;
- }
- }
-
- static class S {
- public final Provider<S> sProvider;
- @Inject public Lazy<S> sLazy;
-
- @Inject
- S(Provider<S> sProvider) {
- this.sProvider = sProvider;
- }
- }
-
- static class X {
- public final Y y;
-
- @Inject
- X(Y y) {
- this.y = y;
- }
- }
-
- static class Y {
- public final Map<String, Provider<X>> mapOfProvidersOfX;
- public final Map<String, Provider<Y>> mapOfProvidersOfY;
-
- @Inject
- Y(Map<String, Provider<X>> mapOfProvidersOfX, Map<String, Provider<Y>> mapOfProvidersOfY) {
- this.mapOfProvidersOfX = mapOfProvidersOfX;
- this.mapOfProvidersOfY = mapOfProvidersOfY;
- }
- }
-
- @Module
- abstract static class CycleMapModule {
- @Binds
- @IntoMap
- @StringKey("X")
- abstract X x(X x);
-
- @Binds
- @IntoMap
- @StringKey("Y")
- abstract Y y(Y y);
- }
-
- @SuppressWarnings("dependency-cycle")
- @Component(modules = CycleMapModule.class)
- interface CycleMapComponent {
- Y y();
- }
-
- @SuppressWarnings("dependency-cycle")
- @Component(modules = CycleModule.class)
- interface CycleComponent {
- A a();
-
- C c();
-
- ChildCycleComponent child();
- }
-
- @Module
- static class CycleModule {
- @Provides
- static Object provideObjectWithCycle(@SuppressWarnings("unused") Provider<Object> object) {
- return "object";
- }
- }
-
- @SuppressWarnings("dependency-cycle")
- @Component
- interface SelfCycleComponent {
- S s();
- }
-
- @Subcomponent
- interface ChildCycleComponent {
- @SuppressWarnings("dependency-cycle")
- A a();
-
- @SuppressWarnings("dependency-cycle")
- Object object();
- }
-
- interface Foo {}
-
- static class Bar implements Foo {
- @Inject
- Bar(Provider<Foo> fooProvider) {}
- }
-
- /**
- * A component with a cycle in which a {@code @Binds} binding depends on the binding that has to
- * be deferred.
- */
- @Component(modules = BindsCycleModule.class)
- interface BindsCycleComponent {
- Bar bar();
- }
-
- @Module
- abstract static class BindsCycleModule {
- @Binds
- abstract Foo foo(Bar bar);
- }
-}
diff --git a/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java b/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java
deleted file mode 100644
index b77ee3e..0000000
--- a/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java
+++ /dev/null
@@ -1,240 +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.functional.cycle;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.lang.Thread.State.BLOCKED;
-import static java.lang.Thread.State.WAITING;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.junit.Assert.fail;
-
-import com.google.common.util.concurrent.SettableFuture;
-import com.google.common.util.concurrent.Uninterruptibles;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DoubleCheckCycleTest {
- // TODO(b/77916397): Migrate remaining tests in DoubleCheckTest to functional tests in this class.
-
- /** A qualifier for a reentrant scoped binding. */
- @Retention(RUNTIME)
- @Qualifier
- @interface Reentrant {}
-
- /** A module to be overridden in each test. */
- @Module
- static class OverrideModule {
- @Provides
- @Singleton
- Object provideObject() {
- throw new IllegalStateException("This method should be overridden in tests");
- }
-
- @Provides
- @Singleton
- @Reentrant
- Object provideReentrantObject(@Reentrant Provider<Object> provider) {
- throw new IllegalStateException("This method should be overridden in tests");
- }
- }
-
- @Singleton
- @Component(modules = OverrideModule.class)
- interface TestComponent {
- Object getObject();
- @Reentrant Object getReentrantObject();
- }
-
- @Test
- public void testNonReentrant() {
- AtomicInteger callCount = new AtomicInteger(0);
-
- // Provides a non-reentrant binding. The provides method should only be called once.
- DoubleCheckCycleTest.TestComponent component =
- DaggerDoubleCheckCycleTest_TestComponent.builder()
- .overrideModule(
- new OverrideModule() {
- @Override Object provideObject() {
- callCount.getAndIncrement();
- return new Object();
- }
- })
- .build();
-
- assertThat(callCount.get()).isEqualTo(0);
- Object first = component.getObject();
- assertThat(callCount.get()).isEqualTo(1);
- Object second = component.getObject();
- assertThat(callCount.get()).isEqualTo(1);
- assertThat(first).isSameInstanceAs(second);
- }
-
- @Test
- public void testReentrant() {
- AtomicInteger callCount = new AtomicInteger(0);
-
- // Provides a reentrant binding. Even though it's scoped, the provides method is called twice.
- // In this case, we allow it since the same instance is returned on the second call.
- DoubleCheckCycleTest.TestComponent component =
- DaggerDoubleCheckCycleTest_TestComponent.builder()
- .overrideModule(
- new OverrideModule() {
- @Override Object provideReentrantObject(Provider<Object> provider) {
- if (callCount.incrementAndGet() == 1) {
- return provider.get();
- }
- return new Object();
- }
- })
- .build();
-
- assertThat(callCount.get()).isEqualTo(0);
- Object first = component.getReentrantObject();
- assertThat(callCount.get()).isEqualTo(2);
- Object second = component.getReentrantObject();
- assertThat(callCount.get()).isEqualTo(2);
- assertThat(first).isSameInstanceAs(second);
- }
-
- @Test
- public void testFailingReentrant() {
- AtomicInteger callCount = new AtomicInteger(0);
-
- // Provides a failing reentrant binding. Even though it's scoped, the provides method is called
- // twice. In this case we throw an exception since a different instance is provided on the
- // second call.
- DoubleCheckCycleTest.TestComponent component =
- DaggerDoubleCheckCycleTest_TestComponent.builder()
- .overrideModule(
- new OverrideModule() {
- @Override Object provideReentrantObject(Provider<Object> provider) {
- if (callCount.incrementAndGet() == 1) {
- provider.get();
- return new Object();
- }
- return new Object();
- }
- })
- .build();
-
- assertThat(callCount.get()).isEqualTo(0);
- try {
- component.getReentrantObject();
- fail("Expected IllegalStateException");
- } catch (IllegalStateException e) {
- assertThat(e).hasMessageThat().contains("Scoped provider was invoked recursively");
- }
- assertThat(callCount.get()).isEqualTo(2);
- }
-
- @Test(timeout = 5000)
-
- public void testGetFromMultipleThreads() throws Exception {
- AtomicInteger callCount = new AtomicInteger(0);
- AtomicInteger requestCount = new AtomicInteger(0);
- SettableFuture<Object> future = SettableFuture.create();
-
- // Provides a non-reentrant binding. In this case, we return a SettableFuture so that we can
- // control when the provides method returns.
- DoubleCheckCycleTest.TestComponent component =
- DaggerDoubleCheckCycleTest_TestComponent.builder()
- .overrideModule(
- new OverrideModule() {
- @Override
- Object provideObject() {
- callCount.incrementAndGet();
- try {
- return Uninterruptibles.getUninterruptibly(future);
- } catch (ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- })
- .build();
-
- int numThreads = 10;
- CountDownLatch remainingTasks = new CountDownLatch(numThreads);
- List<Thread> tasks = new ArrayList<>(numThreads);
- List<Object> values = Collections.synchronizedList(new ArrayList<>(numThreads));
-
- // Set up multiple threads that call component.getObject().
- for (int i = 0; i < numThreads; i++) {
- tasks.add(
- new Thread(
- () -> {
- requestCount.incrementAndGet();
- values.add(component.getObject());
- remainingTasks.countDown();
- }));
- }
-
- // Check initial conditions
- assertThat(remainingTasks.getCount()).isEqualTo(10);
- assertThat(requestCount.get()).isEqualTo(0);
- assertThat(callCount.get()).isEqualTo(0);
- assertThat(values).isEmpty();
-
- // Start all threads
- tasks.forEach(Thread::start);
-
- // Wait for all threads to wait/block.
- long waiting = 0;
- while (waiting != numThreads) {
- waiting =
- tasks.stream()
- .map(Thread::getState)
- .filter(state -> state == WAITING || state == BLOCKED)
- .count();
- }
-
- // Check the intermediate state conditions.
- // * All 10 threads should have requested the binding, but none should have finished.
- // * Only 1 thread should have reached the provides method.
- // * None of the threads should have set a value (since they are waiting for future to be set).
- assertThat(remainingTasks.getCount()).isEqualTo(10);
- assertThat(requestCount.get()).isEqualTo(10);
- assertThat(callCount.get()).isEqualTo(1);
- assertThat(values).isEmpty();
-
- // Set the future and wait on all remaining threads to finish.
- Object futureValue = new Object();
- future.set(futureValue);
- remainingTasks.await();
-
- // Check the final state conditions.
- // All values should be set now, and they should all be equal to the same instance.
- assertThat(remainingTasks.getCount()).isEqualTo(0);
- assertThat(requestCount.get()).isEqualTo(10);
- assertThat(callCount.get()).isEqualTo(1);
- assertThat(values).isEqualTo(Collections.nCopies(numThreads, futureValue));
- }
-}
diff --git a/javatests/dagger/functional/cycle/LongCycle.java b/javatests/dagger/functional/cycle/LongCycle.java
deleted file mode 100644
index 1b3fb24..0000000
--- a/javatests/dagger/functional/cycle/LongCycle.java
+++ /dev/null
@@ -1,140 +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.functional.cycle;
-
-import dagger.Component;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Component with a long enough cycle such that the initialization of a provider happens in a
- * separate {@code initialize} method from the one where it is used as a delegated factory.
- *
- */
-// Each nested class's constructor has an intentionally unused parameter.
-@SuppressWarnings("unused")
-final class LongCycle {
- static class Class1 { @Inject Class1(Class2 class2) {} }
- static class Class2 { @Inject Class2(Class3 class3) {} }
- static class Class3 { @Inject Class3(Class4 class4) {} }
- static class Class4 { @Inject Class4(Class5 class5) {} }
- static class Class5 { @Inject Class5(Class6 class6) {} }
- static class Class6 { @Inject Class6(Class7 class7) {} }
- static class Class7 { @Inject Class7(Class8 class8) {} }
- static class Class8 { @Inject Class8(Class9 class9) {} }
- static class Class9 { @Inject Class9(Class10 class10) {} }
- static class Class10 { @Inject Class10(Class11 class11) {} }
- static class Class11 { @Inject Class11(Class12 class12) {} }
- static class Class12 { @Inject Class12(Class13 class13) {} }
- static class Class13 { @Inject Class13(Class14 class14) {} }
- static class Class14 { @Inject Class14(Class15 class15) {} }
- static class Class15 { @Inject Class15(Class16 class16) {} }
- static class Class16 { @Inject Class16(Class17 class17) {} }
- static class Class17 { @Inject Class17(Class18 class18) {} }
- static class Class18 { @Inject Class18(Class19 class19) {} }
- static class Class19 { @Inject Class19(Class20 class20) {} }
- static class Class20 { @Inject Class20(Class21 class21) {} }
- static class Class21 { @Inject Class21(Class22 class22) {} }
- static class Class22 { @Inject Class22(Class23 class23) {} }
- static class Class23 { @Inject Class23(Class24 class24) {} }
- static class Class24 { @Inject Class24(Class25 class25) {} }
- static class Class25 { @Inject Class25(Class26 class26) {} }
- static class Class26 { @Inject Class26(Class27 class27) {} }
- static class Class27 { @Inject Class27(Class28 class28) {} }
- static class Class28 { @Inject Class28(Class29 class29) {} }
- static class Class29 { @Inject Class29(Class30 class30) {} }
- static class Class30 { @Inject Class30(Class31 class31) {} }
- static class Class31 { @Inject Class31(Class32 class32) {} }
- static class Class32 { @Inject Class32(Class33 class33) {} }
- static class Class33 { @Inject Class33(Class34 class34) {} }
- static class Class34 { @Inject Class34(Class35 class35) {} }
- static class Class35 { @Inject Class35(Class36 class36) {} }
- static class Class36 { @Inject Class36(Class37 class37) {} }
- static class Class37 { @Inject Class37(Class38 class38) {} }
- static class Class38 { @Inject Class38(Class39 class39) {} }
- static class Class39 { @Inject Class39(Class40 class40) {} }
- static class Class40 { @Inject Class40(Class41 class41) {} }
- static class Class41 { @Inject Class41(Class42 class42) {} }
- static class Class42 { @Inject Class42(Class43 class43) {} }
- static class Class43 { @Inject Class43(Class44 class44) {} }
- static class Class44 { @Inject Class44(Class45 class45) {} }
- static class Class45 { @Inject Class45(Class46 class46) {} }
- static class Class46 { @Inject Class46(Class47 class47) {} }
- static class Class47 { @Inject Class47(Class48 class48) {} }
- static class Class48 { @Inject Class48(Class49 class49) {} }
- static class Class49 { @Inject Class49(Class50 class50) {} }
- static class Class50 { @Inject Class50(Class51 class51) {} }
- static class Class51 { @Inject Class51(Class52 class52) {} }
- static class Class52 { @Inject Class52(Class53 class53) {} }
- static class Class53 { @Inject Class53(Class54 class54) {} }
- static class Class54 { @Inject Class54(Class55 class55) {} }
- static class Class55 { @Inject Class55(Class56 class56) {} }
- static class Class56 { @Inject Class56(Class57 class57) {} }
- static class Class57 { @Inject Class57(Class58 class58) {} }
- static class Class58 { @Inject Class58(Class59 class59) {} }
- static class Class59 { @Inject Class59(Class60 class60) {} }
- static class Class60 { @Inject Class60(Class61 class61) {} }
- static class Class61 { @Inject Class61(Class62 class62) {} }
- static class Class62 { @Inject Class62(Class63 class63) {} }
- static class Class63 { @Inject Class63(Class64 class64) {} }
- static class Class64 { @Inject Class64(Class65 class65) {} }
- static class Class65 { @Inject Class65(Class66 class66) {} }
- static class Class66 { @Inject Class66(Class67 class67) {} }
- static class Class67 { @Inject Class67(Class68 class68) {} }
- static class Class68 { @Inject Class68(Class69 class69) {} }
- static class Class69 { @Inject Class69(Class70 class70) {} }
- static class Class70 { @Inject Class70(Class71 class71) {} }
- static class Class71 { @Inject Class71(Class72 class72) {} }
- static class Class72 { @Inject Class72(Class73 class73) {} }
- static class Class73 { @Inject Class73(Class74 class74) {} }
- static class Class74 { @Inject Class74(Class75 class75) {} }
- static class Class75 { @Inject Class75(Class76 class76) {} }
- static class Class76 { @Inject Class76(Class77 class77) {} }
- static class Class77 { @Inject Class77(Class78 class78) {} }
- static class Class78 { @Inject Class78(Class79 class79) {} }
- static class Class79 { @Inject Class79(Class80 class80) {} }
- static class Class80 { @Inject Class80(Class81 class81) {} }
- static class Class81 { @Inject Class81(Class82 class82) {} }
- static class Class82 { @Inject Class82(Class83 class83) {} }
- static class Class83 { @Inject Class83(Class84 class84) {} }
- static class Class84 { @Inject Class84(Class85 class85) {} }
- static class Class85 { @Inject Class85(Class86 class86) {} }
- static class Class86 { @Inject Class86(Class87 class87) {} }
- static class Class87 { @Inject Class87(Class88 class88) {} }
- static class Class88 { @Inject Class88(Class89 class89) {} }
- static class Class89 { @Inject Class89(Class90 class90) {} }
- static class Class90 { @Inject Class90(Class91 class91) {} }
- static class Class91 { @Inject Class91(Class92 class92) {} }
- static class Class92 { @Inject Class92(Class93 class93) {} }
- static class Class93 { @Inject Class93(Class94 class94) {} }
- static class Class94 { @Inject Class94(Class95 class95) {} }
- static class Class95 { @Inject Class95(Class96 class96) {} }
- static class Class96 { @Inject Class96(Class97 class97) {} }
- static class Class97 { @Inject Class97(Class98 class98) {} }
- static class Class98 { @Inject Class98(Class99 class99) {} }
- static class Class99 { @Inject Class99(Class100 class100) {} }
- static class Class100 { @Inject Class100(Class101 class101) {} }
- static class Class101 { @Inject Class101(Provider<Class1> class1Provider) {} }
-
- @SuppressWarnings("dependency-cycle")
- @Component
- interface LongCycleComponent {
- Class1 class1();
- }
-
- private LongCycle() {}
-}
diff --git a/javatests/dagger/functional/cycle/LongCycleTest.java b/javatests/dagger/functional/cycle/LongCycleTest.java
deleted file mode 100644
index a6244b1..0000000
--- a/javatests/dagger/functional/cycle/LongCycleTest.java
+++ /dev/null
@@ -1,58 +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.functional.cycle;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-import static com.google.common.truth.TruthJUnit.assume;
-import static java.util.Arrays.stream;
-
-import dagger.functional.cycle.LongCycle.LongCycleComponent;
-import java.lang.reflect.Method;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class LongCycleTest {
-
- /**
- * Tests a cycle long enough that the real factory is created in a separate initialize method from
- * the delegate factory.
- */
- @Test
- public void longCycle() {
- LongCycleComponent longCycleComponent = DaggerLongCycle_LongCycleComponent.create();
- assertThat(longCycleComponent.class1()).isNotNull();
- }
-
- /**
- * Fails if {@link LongCycleComponent} doesn't have a long enough cycle to make sure the real
- * factory is created in a separate method from the delegate factory.
- */
- @Test
- public void longCycleHasMoreThanOneInitializeMethod() {
- assume().that(System.getProperty("dagger.mode")).doesNotContain("FastInit");
- boolean hasInitialize2 =
- stream(DaggerLongCycle_LongCycleComponent.class.getDeclaredMethods())
- .map(Method::getName)
- .anyMatch(name -> name.equals("initialize2"));
- assertWithMessage("LongCycleComponent impl has an initialize2 method")
- .that(hasInitialize2)
- .isTrue();
- }
-}
diff --git a/javatests/dagger/functional/factory/AbstractModule.java b/javatests/dagger/functional/factory/AbstractModule.java
deleted file mode 100644
index 83a13d6..0000000
--- a/javatests/dagger/functional/factory/AbstractModule.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.functional.factory;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-abstract class AbstractModule {
- @Provides
- static String provideString() {
- return "foo";
- }
-}
diff --git a/javatests/dagger/functional/factory/ConcreteModuleThatCouldBeAbstract.java b/javatests/dagger/functional/factory/ConcreteModuleThatCouldBeAbstract.java
deleted file mode 100644
index 32591a2..0000000
--- a/javatests/dagger/functional/factory/ConcreteModuleThatCouldBeAbstract.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.functional.factory;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class ConcreteModuleThatCouldBeAbstract {
- @Provides
- static double provideDouble() {
- return 42.0;
- }
-}
diff --git a/javatests/dagger/functional/factory/Dependency.java b/javatests/dagger/functional/factory/Dependency.java
deleted file mode 100644
index 90dc294..0000000
--- a/javatests/dagger/functional/factory/Dependency.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.factory;
-
-final class Dependency {
- Object object() {
- return "bar";
- }
-}
diff --git a/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java b/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java
deleted file mode 100644
index 83505e9..0000000
--- a/javatests/dagger/functional/factory/FactoryBindsInstanceTest.java
+++ /dev/null
@@ -1,101 +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.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.junit.Assert.fail;
-
-import dagger.BindsInstance;
-import dagger.Component;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for component factories with {@link BindsInstance} parameters. */
-@RunWith(JUnit4.class)
-public final class FactoryBindsInstanceTest {
-
- @Component
- interface BindsInstanceComponent {
- String string();
-
- @Component.Factory
- interface Factory {
- BindsInstanceComponent create(@BindsInstance String string);
- }
- }
-
- @Test
- public void bindsInstance() {
- BindsInstanceComponent component =
- DaggerFactoryBindsInstanceTest_BindsInstanceComponent.factory().create("baz");
- assertThat(component.string()).isEqualTo("baz");
- }
-
- @Test
- public void nonNullableBindsInstance_failsOnNull() {
- try {
- DaggerFactoryBindsInstanceTest_BindsInstanceComponent.factory().create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Target({METHOD, PARAMETER})
- @Retention(RUNTIME)
- @interface Nullable {}
-
- @Component
- interface NullableBindsInstanceComponent {
- @Nullable
- String string();
-
- @Component.Factory
- interface Factory {
- NullableBindsInstanceComponent create(@BindsInstance @Nullable String string);
- }
- }
-
- @Test
- public void nullableBindsInstance_doesNotFailOnNull() {
- NullableBindsInstanceComponent component =
- DaggerFactoryBindsInstanceTest_NullableBindsInstanceComponent.factory().create(null);
- assertThat(component.string()).isEqualTo(null);
- }
-
- @Component
- interface PrimitiveBindsInstanceComponent {
- int getInt();
-
- @Component.Factory
- interface Factory {
- PrimitiveBindsInstanceComponent create(@BindsInstance int i);
- }
- }
-
- @Test
- public void primitiveBindsInstance() {
- PrimitiveBindsInstanceComponent component =
- DaggerFactoryBindsInstanceTest_PrimitiveBindsInstanceComponent.factory().create(1);
- assertThat(component.getInt()).isEqualTo(1);
- }
-}
diff --git a/javatests/dagger/functional/factory/FactoryDependenciesTest.java b/javatests/dagger/functional/factory/FactoryDependenciesTest.java
deleted file mode 100644
index 35a0b85..0000000
--- a/javatests/dagger/functional/factory/FactoryDependenciesTest.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.functional.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for factories for components with a dependency. */
-@RunWith(JUnit4.class)
-public final class FactoryDependenciesTest {
-
- @Component(dependencies = Dependency.class)
- interface DependencyComponent {
- Object object();
-
- @Component.Factory
- interface Factory {
- DependencyComponent create(Dependency dependency);
- }
- }
-
- @Test
- public void dependency() {
- DependencyComponent component =
- DaggerFactoryDependenciesTest_DependencyComponent.factory().create(new Dependency());
- assertThat(component.object()).isEqualTo("bar");
- }
-
- @Test
- public void dependency_failsOnNull() {
- try {
- DaggerFactoryDependenciesTest_DependencyComponent.factory().create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/functional/factory/FactoryImplicitModulesTest.java b/javatests/dagger/functional/factory/FactoryImplicitModulesTest.java
deleted file mode 100644
index 143f322..0000000
--- a/javatests/dagger/functional/factory/FactoryImplicitModulesTest.java
+++ /dev/null
@@ -1,154 +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.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for factories for components with modules that do not require an instance to be passed to
- * the factory. Includes both tests where the module does not have a corresponding parameter in the
- * factory method and where it does have a parameter, for cases where that's allowed.
- */
-@RunWith(JUnit4.class)
-public final class FactoryImplicitModulesTest {
-
- @Component(modules = AbstractModule.class)
- interface AbstractModuleComponent {
- String string();
-
- @Component.Factory
- interface Factory {
- AbstractModuleComponent create();
- }
- }
-
- @Test
- public void abstractModule() {
- AbstractModuleComponent component =
- DaggerFactoryImplicitModulesTest_AbstractModuleComponent.factory().create();
- assertThat(component.string()).isEqualTo("foo");
- }
-
- @Component(modules = InstantiableConcreteModule.class)
- interface InstantiableConcreteModuleComponent {
- int getInt();
-
- @Component.Factory
- interface Factory {
- InstantiableConcreteModuleComponent create();
- }
- }
-
- @Test
- public void instantiableConcreteModule() {
- InstantiableConcreteModuleComponent component =
- DaggerFactoryImplicitModulesTest_InstantiableConcreteModuleComponent.factory().create();
- assertThat(component.getInt()).isEqualTo(42);
- }
-
- @Component(modules = InstantiableConcreteModule.class)
- interface InstantiableConcreteModuleWithFactoryParameterComponent {
- int getInt();
-
- @Component.Factory
- interface Factory {
- InstantiableConcreteModuleWithFactoryParameterComponent create(
- InstantiableConcreteModule module);
- }
- }
-
- @Test
- public void instantiableConcreteModule_withFactoryParameter() {
- InstantiableConcreteModuleWithFactoryParameterComponent component =
- DaggerFactoryImplicitModulesTest_InstantiableConcreteModuleWithFactoryParameterComponent
- .factory()
- .create(new InstantiableConcreteModule());
- assertThat(component.getInt()).isEqualTo(42);
- }
-
- @Test
- public void instantiableConcreteModule_withFactoryParameter_failsOnNull() {
- try {
- DaggerFactoryImplicitModulesTest_InstantiableConcreteModuleWithFactoryParameterComponent
- .factory()
- .create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Component(modules = ConcreteModuleThatCouldBeAbstract.class)
- interface ConcreteModuleThatCouldBeAbstractComponent {
- double getDouble();
-
- @Component.Factory
- interface Factory {
- ConcreteModuleThatCouldBeAbstractComponent create();
- }
- }
-
- @Test
- public void concreteModuleThatCouldBeAbstract() {
- ConcreteModuleThatCouldBeAbstractComponent component =
- DaggerFactoryImplicitModulesTest_ConcreteModuleThatCouldBeAbstractComponent.factory()
- .create();
- assertThat(component.getDouble()).isEqualTo(42.0);
- }
-
- @Component(modules = ConcreteModuleThatCouldBeAbstract.class)
- interface ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent {
- double getDouble();
-
- @Component.Factory
- interface Factory {
- ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent create(
- ConcreteModuleThatCouldBeAbstract module);
- }
- }
-
- @Test
- public void concreteModuleThatCouldBeAbstract_withFactoryParameter() {
- ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent component =
- DaggerFactoryImplicitModulesTest_ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent
- .factory()
- .create(new ConcreteModuleThatCouldBeAbstract());
- assertThat(component.getDouble()).isEqualTo(42.0);
- }
-
- @Test
- public void concreteModuleThatCouldBeAbstract_withFactoryParameter_failsOnNull() {
- // This matches what builders do when there's a setter for such a module; the setter checks that
- // the argument is not null but otherwise ignores it.
- // It's possible that we shouldn't even allow such a parameter for a factory, since unlike a
- // builder, where the setter can just not be called, a factory doesn't give the option of not
- // passing *something* for the unused parameter.
- try {
- ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent component =
- DaggerFactoryImplicitModulesTest_ConcreteModuleThatCouldBeAbstractWithFactoryParameterComponent
- .factory()
- .create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/functional/factory/FactoryMixedParametersTest.java b/javatests/dagger/functional/factory/FactoryMixedParametersTest.java
deleted file mode 100644
index 733c673..0000000
--- a/javatests/dagger/functional/factory/FactoryMixedParametersTest.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.functional.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.BindsInstance;
-import dagger.Component;
-import java.util.Random;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for component factories with multiple parameters. */
-@RunWith(JUnit4.class)
-public final class FactoryMixedParametersTest {
-
- @Component(
- modules = {
- AbstractModule.class,
- UninstantiableConcreteModule.class,
- InstantiableConcreteModule.class
- },
- dependencies = Dependency.class)
- interface MixedArgComponent {
- String string();
- int getInt();
- long getLong();
- Object object();
- double getDouble();
- Provider<Random> randomProvider();
-
- @Component.Factory
- interface Factory {
- MixedArgComponent create(
- @BindsInstance double d,
- Dependency dependency,
- UninstantiableConcreteModule module,
- @BindsInstance Random random);
- }
- }
-
- @Test
- public void mixedArgComponent() {
- Random random = new Random();
- MixedArgComponent component =
- DaggerFactoryMixedParametersTest_MixedArgComponent.factory()
- .create(3.0, new Dependency(), new UninstantiableConcreteModule(2L), random);
- assertThat(component.string()).isEqualTo("foo");
- assertThat(component.getInt()).isEqualTo(42);
- assertThat(component.getDouble()).isEqualTo(3.0);
- assertThat(component.object()).isEqualTo("bar");
- assertThat(component.getLong()).isEqualTo(2L);
- assertThat(component.randomProvider().get()).isSameInstanceAs(random);
- assertThat(component.randomProvider().get()).isSameInstanceAs(random);
- }
-}
diff --git a/javatests/dagger/functional/factory/FactoryRequiredModulesTest.java b/javatests/dagger/functional/factory/FactoryRequiredModulesTest.java
deleted file mode 100644
index 5b81b51..0000000
--- a/javatests/dagger/functional/factory/FactoryRequiredModulesTest.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.functional.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for factories for components that have a module that must have an instance provided by the
- * user.
- */
-@RunWith(JUnit4.class)
-public final class FactoryRequiredModulesTest {
-
- @Component(modules = UninstantiableConcreteModule.class)
- interface UninstantiableConcreteModuleComponent {
- long getLong();
-
- @Component.Factory
- interface Factory {
- UninstantiableConcreteModuleComponent create(UninstantiableConcreteModule module);
- }
- }
-
- @Test
- public void uninstantiableConcreteModule() {
- UninstantiableConcreteModuleComponent component =
- DaggerFactoryRequiredModulesTest_UninstantiableConcreteModuleComponent.factory()
- .create(new UninstantiableConcreteModule(42L));
- assertThat(component.getLong()).isEqualTo(42L);
- }
-
- @Test
- public void uninstantiableConcreteModule_failsOnNull() {
- try {
- DaggerFactoryRequiredModulesTest_UninstantiableConcreteModuleComponent.factory().create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/functional/factory/InstantiableConcreteModule.java b/javatests/dagger/functional/factory/InstantiableConcreteModule.java
deleted file mode 100644
index 37acbe0..0000000
--- a/javatests/dagger/functional/factory/InstantiableConcreteModule.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.factory;
-
-import dagger.Module;
-import dagger.Provides;
-
-@SuppressWarnings("StaticModuleMethods") // intentionally non-static
-@Module
-final class InstantiableConcreteModule {
- @Provides
- int provideInt() {
- return 42;
- }
-}
diff --git a/javatests/dagger/functional/factory/SubcomponentFactoryTest.java b/javatests/dagger/functional/factory/SubcomponentFactoryTest.java
deleted file mode 100644
index cbff8a1..0000000
--- a/javatests/dagger/functional/factory/SubcomponentFactoryTest.java
+++ /dev/null
@@ -1,110 +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.factory;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.BindsInstance;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import javax.inject.Inject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for {@linkplain Subcomponent.Factory subcomponent factories}.
- *
- * <p>Most things are tested in {@code FactoryTest}; this is just intended to test some things like
- * injecting subcomponent factories and returning them from component methods.
- */
-@RunWith(JUnit4.class)
-public final class SubcomponentFactoryTest {
-
- @Component
- interface ParentWithSubcomponentFactory {
- Sub.Factory subcomponentFactory();
-
- @Component.Factory
- interface Factory {
- ParentWithSubcomponentFactory create(@BindsInstance int i);
- }
- }
-
- @Subcomponent
- interface Sub {
- int i();
- String s();
-
- @Subcomponent.Factory
- interface Factory {
- Sub create(@BindsInstance String s);
- }
- }
-
- @Test
- public void parentComponentWithSubcomponentFactoryEntryPoint() {
- ParentWithSubcomponentFactory parent =
- DaggerSubcomponentFactoryTest_ParentWithSubcomponentFactory.factory().create(3);
- Sub subcomponent = parent.subcomponentFactory().create("foo");
- assertThat(subcomponent.i()).isEqualTo(3);
- assertThat(subcomponent.s()).isEqualTo("foo");
- }
-
- @Module(subcomponents = Sub.class)
- abstract static class ModuleWithSubcomponent {
- @Provides
- static int provideInt() {
- return 42;
- }
- }
-
- static class UsesSubcomponentFactory {
- private final Sub.Factory subFactory;
-
- @Inject
- UsesSubcomponentFactory(Sub.Factory subFactory) {
- this.subFactory = subFactory;
- }
-
- Sub getSubcomponent(String s) {
- return subFactory.create(s);
- }
- }
-
- @Component(modules = ModuleWithSubcomponent.class)
- interface ParentWithModuleWithSubcomponent {
- UsesSubcomponentFactory usesSubcomponentFactory();
- }
-
- @Test
- public void parentComponentWithModuleWithSubcomponent() {
- ParentWithModuleWithSubcomponent parent =
- DaggerSubcomponentFactoryTest_ParentWithModuleWithSubcomponent.create();
- UsesSubcomponentFactory usesSubcomponentFactory = parent.usesSubcomponentFactory();
-
- Sub subcomponent1 = usesSubcomponentFactory.getSubcomponent("foo");
- assertThat(subcomponent1.i()).isEqualTo(42);
- assertThat(subcomponent1.s()).isEqualTo("foo");
-
- Sub subcomponent2 = usesSubcomponentFactory.getSubcomponent("bar");
- assertThat(subcomponent2.i()).isEqualTo(42);
- assertThat(subcomponent2.s()).isEqualTo("bar");
- }
-}
diff --git a/javatests/dagger/functional/factory/UninstantiableConcreteModule.java b/javatests/dagger/functional/factory/UninstantiableConcreteModule.java
deleted file mode 100644
index 13f50fd..0000000
--- a/javatests/dagger/functional/factory/UninstantiableConcreteModule.java
+++ /dev/null
@@ -1,34 +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.factory;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class UninstantiableConcreteModule {
- private final long l;
-
- UninstantiableConcreteModule(long l) {
- this.l = l;
- }
-
- @Provides
- long provideLong() {
- return l;
- }
-}
diff --git a/javatests/dagger/functional/guava/BUILD b/javatests/dagger/functional/guava/BUILD
deleted file mode 100644
index 66492eb..0000000
--- a/javatests/dagger/functional/guava/BUILD
+++ /dev/null
@@ -1,36 +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:
-# 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")
-
-GenJavaTests(
- name = "guava_tests",
- srcs = glob(["**/*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
- "@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/truth",
- ],
-)
diff --git a/javatests/dagger/functional/guava/OptionalBindingComponents.java b/javatests/dagger/functional/guava/OptionalBindingComponents.java
deleted file mode 100644
index ee58865..0000000
--- a/javatests/dagger/functional/guava/OptionalBindingComponents.java
+++ /dev/null
@@ -1,151 +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.functional.guava;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Optional;
-import dagger.BindsOptionalOf;
-import dagger.Component;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import java.lang.annotation.Retention;
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-/** Classes to support testing {@code BindsOptionalOf} functionality. */
-public final class OptionalBindingComponents {
-
- /** A qualifier. */
- @Qualifier
- @Retention(RUNTIME)
- public @interface SomeQualifier {}
-
- /** A value object that contains various optionally-bound objects. */
- @AutoValue
- public abstract static class Values {
- abstract Optional<Value> optionalInstance();
-
- abstract Optional<Provider<Value>> optionalProvider();
-
- abstract Optional<Lazy<Value>> optionalLazy();
-
- abstract Optional<Provider<Lazy<Value>>> optionalLazyProvider();
- }
-
- // Default access so that it's inaccessible to OptionalBindingComponentsWithInaccessibleTypes.
- enum Value {
- VALUE,
- QUALIFIED_VALUE
- }
-
- static final class InjectedThing {
- @Inject
- InjectedThing() {}
- }
-
- /** Binds optionals and {@link Values}. */
- @Module
- public abstract static class OptionalBindingModule {
- @BindsOptionalOf
- abstract Value value();
-
- @BindsOptionalOf
- @SomeQualifier abstract Value qualifiedValue();
-
- // Valid because it's qualified.
- @BindsOptionalOf
- @SomeQualifier abstract InjectedThing qualifiedInjectedThing();
-
- @BindsOptionalOf
- abstract Object nullableObject();
-
- @Provides
- static Values values(
- Optional<Value> optionalInstance,
- Optional<Provider<Value>> optionalProvider,
- Optional<Lazy<Value>> optionalLazy,
- Optional<Provider<Lazy<Value>>> optionalLazyProvider) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProvider, optionalLazy, optionalLazyProvider);
- }
-
- @Provides
- @SomeQualifier
- static Values qualifiedValues(
- @SomeQualifier Optional<Value> optionalInstance,
- @SomeQualifier Optional<Provider<Value>> optionalProvider,
- @SomeQualifier Optional<Lazy<Value>> optionalLazy,
- @SomeQualifier Optional<Provider<Lazy<Value>>> optionalLazyProvider) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProvider, optionalLazy, optionalLazyProvider);
- }
- }
-
- /** Binds {@link Value}. */
- @Module
- public abstract static class ConcreteBindingModule {
- /** @param cycle to demonstrate that optional {@link Provider} injection can break cycles */
- @Provides
- static Value value(Optional<Provider<Value>> cycle) {
- return Value.VALUE;
- }
-
- @Provides
- @SomeQualifier static Value qualifiedValue() {
- return Value.QUALIFIED_VALUE;
- }
-
- @Provides
- @Nullable
- static Object nullableObject() {
- return null;
- }
- }
-
- /** Interface for components used to test optional bindings. */
- public interface OptionalBindingComponent {
- Values values();
-
- @SomeQualifier
- Values qualifiedValues();
-
- // Nullable bindings can satisfy optional bindings except for Optional<Foo>.
-
- Optional<Provider<Object>> optionalNullableProvider();
-
- Optional<Lazy<Object>> optionalNullableLazy();
-
- Optional<Provider<Lazy<Object>>> optionalNullableLazyProvider();
- }
-
- @Component(modules = OptionalBindingModule.class)
- interface AbsentOptionalBindingComponent extends OptionalBindingComponent {
- PresentOptionalBindingSubcomponent presentChild();
- }
-
- @Component(modules = {OptionalBindingModule.class, ConcreteBindingModule.class})
- interface PresentOptionalBindingComponent extends OptionalBindingComponent {}
-
- @Subcomponent(modules = ConcreteBindingModule.class)
- interface PresentOptionalBindingSubcomponent extends OptionalBindingComponent {}
-}
diff --git a/javatests/dagger/functional/guava/OptionalBindingComponentsAbsentTest.java b/javatests/dagger/functional/guava/OptionalBindingComponentsAbsentTest.java
deleted file mode 100644
index d563ace..0000000
--- a/javatests/dagger/functional/guava/OptionalBindingComponentsAbsentTest.java
+++ /dev/null
@@ -1,76 +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.functional.guava;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.guava.OptionalBindingComponents.AbsentOptionalBindingComponent;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for absent optional bindings. */
-@RunWith(JUnit4.class)
-public final class OptionalBindingComponentsAbsentTest {
- private AbsentOptionalBindingComponent absent;
-
- @Before
- public void setUp() {
- absent = DaggerOptionalBindingComponents_AbsentOptionalBindingComponent.create();
- }
-
- @Test
- public void optional() {
- assertThat(absent.values().optionalInstance()).isAbsent();
- }
-
- @Test
- public void optionalProvider() {
- assertThat(absent.values().optionalProvider()).isAbsent();
- }
-
- @Test
- public void optionalLazy() {
- assertThat(absent.values().optionalLazy()).isAbsent();
- }
-
- @Test
- public void optionalLazyProvider() {
- assertThat(absent.values().optionalLazyProvider()).isAbsent();
- }
-
- @Test
- public void qualifiedOptional() {
- assertThat(absent.qualifiedValues().optionalInstance()).isAbsent();
- }
-
- @Test
- public void qualifiedOptionalProvider() {
- assertThat(absent.qualifiedValues().optionalProvider()).isAbsent();
- }
-
- @Test
- public void qualifiedOptionalLazy() {
- assertThat(absent.qualifiedValues().optionalLazy()).isAbsent();
- }
-
- @Test
- public void qualifiedOptionalLazyProvider() {
- assertThat(absent.qualifiedValues().optionalLazyProvider()).isAbsent();
- }
-}
diff --git a/javatests/dagger/functional/guava/OptionalBindingComponentsPresentTest.java b/javatests/dagger/functional/guava/OptionalBindingComponentsPresentTest.java
deleted file mode 100644
index 1243207..0000000
--- a/javatests/dagger/functional/guava/OptionalBindingComponentsPresentTest.java
+++ /dev/null
@@ -1,100 +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.functional.guava;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.functional.guava.OptionalBindingComponents.Value.QUALIFIED_VALUE;
-import static dagger.functional.guava.OptionalBindingComponents.Value.VALUE;
-
-import com.google.common.collect.ImmutableList;
-import dagger.functional.guava.OptionalBindingComponents.OptionalBindingComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for present optional bindings. */
-@RunWith(Parameterized.class)
-public final class OptionalBindingComponentsPresentTest {
-
- @Parameters(name = "{0}")
- public static Iterable<Object[]> parameters() {
- return ImmutableList.copyOf(
- new Object[][] {
- {DaggerOptionalBindingComponents_PresentOptionalBindingComponent.create()},
- {DaggerOptionalBindingComponents_AbsentOptionalBindingComponent.create().presentChild()},
- });
- }
-
- private final OptionalBindingComponent component;
-
- public OptionalBindingComponentsPresentTest(OptionalBindingComponent component) {
- this.component = component;
- }
-
- @Test
- public void optionalProvider() {
- assertThat(component.values().optionalProvider().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void optionalLazy() {
- assertThat(component.values().optionalLazy().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void optionalLazyProvider() {
- assertThat(component.values().optionalLazyProvider().get().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void qualifiedOptional() {
- assertThat(component.qualifiedValues().optionalInstance()).hasValue(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalProvider() {
- assertThat(component.qualifiedValues().optionalProvider().get().get())
- .isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalLazy() {
- assertThat(component.qualifiedValues().optionalLazy().get().get()).isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalLazyProvider() {
- assertThat(component.qualifiedValues().optionalLazyProvider().get().get().get())
- .isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void optionalNullableProvider() {
- assertThat(component.optionalNullableProvider().get().get()).isNull();
- }
-
- @Test
- public void optionalNullableLazy() {
- assertThat(component.optionalNullableLazy().get().get()).isNull();
- }
-
- @Test
- public void optionalNullableLazyProvider() {
- assertThat(component.optionalNullableLazyProvider().get().get().get()).isNull();
- }
-}
diff --git a/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypes.java b/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypes.java
deleted file mode 100644
index 28a6734..0000000
--- a/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypes.java
+++ /dev/null
@@ -1,31 +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.functional.guava.a;
-
-import dagger.Component;
-import dagger.functional.guava.OptionalBindingComponents.ConcreteBindingModule;
-import dagger.functional.guava.OptionalBindingComponents.OptionalBindingComponent;
-import dagger.functional.guava.OptionalBindingComponents.OptionalBindingModule;
-
-final class OptionalBindingComponentsWithInaccessibleTypes {
-
- @Component(modules = OptionalBindingModule.class)
- interface AbsentOptionalBindingComponent extends OptionalBindingComponent {}
-
- @Component(modules = {OptionalBindingModule.class, ConcreteBindingModule.class})
- interface PresentOptionalBindingComponent extends OptionalBindingComponent {}
-}
diff --git a/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypesTest.java b/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypesTest.java
deleted file mode 100644
index 6be593c..0000000
--- a/javatests/dagger/functional/guava/a/OptionalBindingComponentsWithInaccessibleTypesTest.java
+++ /dev/null
@@ -1,31 +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.functional.guava.a;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for optional bindings that include types inaccessible to the component. */
-@RunWith(JUnit4.class)
-public class OptionalBindingComponentsWithInaccessibleTypesTest {
- @Test
- public void components() {
- DaggerOptionalBindingComponentsWithInaccessibleTypes_AbsentOptionalBindingComponent.create();
- DaggerOptionalBindingComponentsWithInaccessibleTypes_PresentOptionalBindingComponent.create();
- }
-}
diff --git a/javatests/dagger/functional/gwt/GwtIncompatibles.java b/javatests/dagger/functional/gwt/GwtIncompatibles.java
deleted file mode 100644
index d65f116..0000000
--- a/javatests/dagger/functional/gwt/GwtIncompatibles.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.functional.gwt;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.Module;
-import dagger.Provides;
-import java.lang.annotation.Retention;
-import javax.inject.Inject;
-
-interface GwtIncompatibles {
- @Retention(RUNTIME)
- @interface GwtIncompatible {}
-
- @GwtIncompatible
- class OnClass {
- @Inject
- OnClass() {}
- }
-
- class OnConstructor {
- @Inject
- @GwtIncompatible
- OnConstructor() {}
- }
-
- @GwtIncompatible
- class OuterClass {
- static class OnOuterClass {
- @Inject
- OnOuterClass() {}
- }
- }
-
- @GwtIncompatible
- class MembersInjectedType {
- @Inject String string;
- }
-
- @GwtIncompatible
- @Module
- class OnModule {
- @Provides
- static String onModule() {
- return "on module";
- }
- }
-
- @Module
- class OnMethod {
- @GwtIncompatible
- @Provides
- static String onMethod() {
- return "on method";
- }
- }
-}
diff --git a/javatests/dagger/functional/gwt/GwtIncompatiblesTest.java b/javatests/dagger/functional/gwt/GwtIncompatiblesTest.java
deleted file mode 100644
index f6f6c41..0000000
--- a/javatests/dagger/functional/gwt/GwtIncompatiblesTest.java
+++ /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.
- */
-
-package dagger.functional.gwt;
-
-import dagger.functional.gwt.GwtIncompatibles.GwtIncompatible;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@code @GwtIncompatible} bindings. */
-@RunWith(JUnit4.class)
-public class GwtIncompatiblesTest {
- @Test
- public void testIncompatible() {
- assertGwtIncompatible(GwtIncompatibles_OnClass_Factory.class);
- assertGwtIncompatible(GwtIncompatibles_OnConstructor_Factory.class);
- assertGwtIncompatible(GwtIncompatibles_OuterClass_OnOuterClass_Factory.class);
-
- assertGwtIncompatible(GwtIncompatibles_MembersInjectedType_MembersInjector.class);
-
- assertGwtIncompatible(GwtIncompatibles_OnModule_OnModuleFactory.class);
- assertGwtIncompatible(GwtIncompatibles_OnMethod_OnMethodFactory.class);
- }
-
- private void assertGwtIncompatible(Class<?> clazz) {
- boolean gwtIncompatible = clazz.isAnnotationPresent(GwtIncompatible.class);
- if (!gwtIncompatible) {
- throw new AssertionError(clazz.getCanonicalName() + " is not @GwtIncompatible");
- }
- }
-}
diff --git a/javatests/dagger/functional/jdk8/BUILD b/javatests/dagger/functional/jdk8/BUILD
deleted file mode 100644
index 6b76ba3..0000000
--- a/javatests/dagger/functional/jdk8/BUILD
+++ /dev/null
@@ -1,37 +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:
-# 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")
-
-GenJavaTests(
- name = "jdk8_tests",
- srcs = glob(["**/*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- test_only_deps = [
- "@google_bazel_common//third_party/java/guava",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth:truth8",
- ],
- deps = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
diff --git a/javatests/dagger/functional/jdk8/OptionalBindingComponents.java b/javatests/dagger/functional/jdk8/OptionalBindingComponents.java
deleted file mode 100644
index 0048f8b..0000000
--- a/javatests/dagger/functional/jdk8/OptionalBindingComponents.java
+++ /dev/null
@@ -1,151 +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.functional.jdk8;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.auto.value.AutoValue;
-import dagger.BindsOptionalOf;
-import dagger.Component;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import java.lang.annotation.Retention;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-/** Classes to support testing {@code BindsOptionalOf} functionality. */
-public final class OptionalBindingComponents {
-
- /** A qualifier. */
- @Qualifier
- @Retention(RUNTIME)
- public @interface SomeQualifier {}
-
- /** A value object that contains various optionally-bound objects. */
- @AutoValue
- public abstract static class Values {
- abstract Optional<Value> optionalInstance();
-
- abstract Optional<Provider<Value>> optionalProvider();
-
- abstract Optional<Lazy<Value>> optionalLazy();
-
- abstract Optional<Provider<Lazy<Value>>> optionalLazyProvider();
- }
-
- // Default access so that it's inaccessible to OptionalBindingComponentsWithInaccessibleTypes.
- enum Value {
- VALUE,
- QUALIFIED_VALUE
- }
-
- static final class InjectedThing {
- @Inject
- InjectedThing() {}
- }
-
- /** Binds optionals and {@link Values}. */
- @Module
- public abstract static class OptionalBindingModule {
- @BindsOptionalOf
- abstract Value value();
-
- @BindsOptionalOf
- @SomeQualifier abstract Value qualifiedValue();
-
- // Valid because it's qualified.
- @BindsOptionalOf
- @SomeQualifier abstract InjectedThing qualifiedInjectedThing();
-
- @BindsOptionalOf
- abstract Object nullableObject();
-
- @Provides
- static Values values(
- Optional<Value> optionalInstance,
- Optional<Provider<Value>> optionalProvider,
- Optional<Lazy<Value>> optionalLazy,
- Optional<Provider<Lazy<Value>>> optionalLazyProvider) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProvider, optionalLazy, optionalLazyProvider);
- }
-
- @Provides
- @SomeQualifier
- static Values qualifiedValues(
- @SomeQualifier Optional<Value> optionalInstance,
- @SomeQualifier Optional<Provider<Value>> optionalProvider,
- @SomeQualifier Optional<Lazy<Value>> optionalLazy,
- @SomeQualifier Optional<Provider<Lazy<Value>>> optionalLazyProvider) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProvider, optionalLazy, optionalLazyProvider);
- }
- }
-
- /** Binds {@link Value}. */
- @Module
- public abstract static class ConcreteBindingModule {
- /** @param cycle to demonstrate that optional {@link Provider} injection can break cycles */
- @Provides
- static Value value(Optional<Provider<Value>> cycle) {
- return Value.VALUE;
- }
-
- @Provides
- @SomeQualifier static Value qualifiedValue() {
- return Value.QUALIFIED_VALUE;
- }
-
- @Provides
- @Nullable
- static Object nullableObject() {
- return null;
- }
- }
-
- /** Interface for components used to test optional bindings. */
- public interface OptionalBindingComponent {
- Values values();
-
- @SomeQualifier
- Values qualifiedValues();
-
- // Nullable bindings can satisfy optional bindings except for Optional<Foo>.
-
- Optional<Provider<Object>> optionalNullableProvider();
-
- Optional<Lazy<Object>> optionalNullableLazy();
-
- Optional<Provider<Lazy<Object>>> optionalNullableLazyProvider();
- }
-
- @Component(modules = OptionalBindingModule.class)
- interface EmptyOptionalBindingComponent extends OptionalBindingComponent {
- PresentOptionalBindingSubcomponent presentChild();
- }
-
- @Component(modules = {OptionalBindingModule.class, ConcreteBindingModule.class})
- interface PresentOptionalBindingComponent extends OptionalBindingComponent {}
-
- @Subcomponent(modules = ConcreteBindingModule.class)
- interface PresentOptionalBindingSubcomponent extends OptionalBindingComponent {}
-}
diff --git a/javatests/dagger/functional/jdk8/OptionalBindingComponentsEmptyTest.java b/javatests/dagger/functional/jdk8/OptionalBindingComponentsEmptyTest.java
deleted file mode 100644
index 21bdd3c..0000000
--- a/javatests/dagger/functional/jdk8/OptionalBindingComponentsEmptyTest.java
+++ /dev/null
@@ -1,76 +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.functional.jdk8;
-
-import static com.google.common.truth.Truth8.assertThat;
-
-import dagger.functional.jdk8.OptionalBindingComponents.EmptyOptionalBindingComponent;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for absent optional bindings. */
-@RunWith(JUnit4.class)
-public final class OptionalBindingComponentsEmptyTest {
- private EmptyOptionalBindingComponent component;
-
- @Before
- public void setUp() {
- component = DaggerOptionalBindingComponents_EmptyOptionalBindingComponent.create();
- }
-
- @Test
- public void optional() {
- assertThat(component.values().optionalInstance()).isEmpty();
- }
-
- @Test
- public void optionalProvider() {
- assertThat(component.values().optionalProvider()).isEmpty();
- }
-
- @Test
- public void optionalLazy() {
- assertThat(component.values().optionalLazy()).isEmpty();
- }
-
- @Test
- public void optionalLazyProvider() {
- assertThat(component.values().optionalLazyProvider()).isEmpty();
- }
-
- @Test
- public void qualifiedOptional() {
- assertThat(component.qualifiedValues().optionalInstance()).isEmpty();
- }
-
- @Test
- public void qualifiedOptionalProvider() {
- assertThat(component.qualifiedValues().optionalProvider()).isEmpty();
- }
-
- @Test
- public void qualifiedOptionalLazy() {
- assertThat(component.qualifiedValues().optionalLazy()).isEmpty();
- }
-
- @Test
- public void qualifiedOptionalLazyProvider() {
- assertThat(component.qualifiedValues().optionalLazyProvider()).isEmpty();
- }
-}
diff --git a/javatests/dagger/functional/jdk8/OptionalBindingComponentsPresentTest.java b/javatests/dagger/functional/jdk8/OptionalBindingComponentsPresentTest.java
deleted file mode 100644
index 50fbefe..0000000
--- a/javatests/dagger/functional/jdk8/OptionalBindingComponentsPresentTest.java
+++ /dev/null
@@ -1,101 +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.functional.jdk8;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth8.assertThat;
-import static dagger.functional.jdk8.OptionalBindingComponents.Value.QUALIFIED_VALUE;
-import static dagger.functional.jdk8.OptionalBindingComponents.Value.VALUE;
-
-import com.google.common.collect.ImmutableList;
-import dagger.functional.jdk8.OptionalBindingComponents.OptionalBindingComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for present optional bindings. */
-@RunWith(Parameterized.class)
-public final class OptionalBindingComponentsPresentTest {
-
- @Parameters(name = "{0}")
- public static Iterable<Object[]> parameters() {
- return ImmutableList.copyOf(
- new Object[][] {
- {DaggerOptionalBindingComponents_PresentOptionalBindingComponent.create()},
- {DaggerOptionalBindingComponents_EmptyOptionalBindingComponent.create().presentChild()},
- });
- }
-
- private final OptionalBindingComponent component;
-
- public OptionalBindingComponentsPresentTest(OptionalBindingComponent component) {
- this.component = component;
- }
-
- @Test
- public void optionalProvider() {
- assertThat(component.values().optionalProvider().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void optionalLazy() {
- assertThat(component.values().optionalLazy().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void optionalLazyProvider() {
- assertThat(component.values().optionalLazyProvider().get().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void qualifiedOptional() {
- assertThat(component.qualifiedValues().optionalInstance()).hasValue(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalProvider() {
- assertThat(component.qualifiedValues().optionalProvider().get().get())
- .isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalLazy() {
- assertThat(component.qualifiedValues().optionalLazy().get().get()).isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalLazyProvider() {
- assertThat(component.qualifiedValues().optionalLazyProvider().get().get().get())
- .isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void optionalNullableProvider() {
- assertThat(component.optionalNullableProvider().get().get()).isNull();
- }
-
- @Test
- public void optionalNullableLazy() {
- assertThat(component.optionalNullableLazy().get().get()).isNull();
- }
-
- @Test
- public void optionalNullableLazyProvider() {
- assertThat(component.optionalNullableLazyProvider().get().get().get()).isNull();
- }
-}
diff --git a/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypes.java b/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypes.java
deleted file mode 100644
index e4abbb6..0000000
--- a/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypes.java
+++ /dev/null
@@ -1,31 +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.functional.jdk8.a;
-
-import dagger.Component;
-import dagger.functional.jdk8.OptionalBindingComponents.ConcreteBindingModule;
-import dagger.functional.jdk8.OptionalBindingComponents.OptionalBindingComponent;
-import dagger.functional.jdk8.OptionalBindingComponents.OptionalBindingModule;
-
-final class OptionalBindingComponentsWithInaccessibleTypes {
-
- @Component(modules = OptionalBindingModule.class)
- interface EmptyOptionalBindingComponent extends OptionalBindingComponent {}
-
- @Component(modules = {OptionalBindingModule.class, ConcreteBindingModule.class})
- interface PresentOptionalBindingComponent extends OptionalBindingComponent {}
-}
diff --git a/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypesTest.java b/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypesTest.java
deleted file mode 100644
index 8e2687a..0000000
--- a/javatests/dagger/functional/jdk8/a/OptionalBindingComponentsWithInaccessibleTypesTest.java
+++ /dev/null
@@ -1,31 +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.functional.jdk8.a;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for optional bindings that include types inaccessible to the component. */
-@RunWith(JUnit4.class)
-public class OptionalBindingComponentsWithInaccessibleTypesTest {
- @Test
- public void components() {
- DaggerOptionalBindingComponentsWithInaccessibleTypes_EmptyOptionalBindingComponent.create();
- DaggerOptionalBindingComponentsWithInaccessibleTypes_PresentOptionalBindingComponent.create();
- }
-}
diff --git a/javatests/dagger/functional/membersinject/ChildOfArrayOfParentOfStringArray.java b/javatests/dagger/functional/membersinject/ChildOfArrayOfParentOfStringArray.java
deleted file mode 100644
index 61bef71..0000000
--- a/javatests/dagger/functional/membersinject/ChildOfArrayOfParentOfStringArray.java
+++ /dev/null
@@ -1,21 +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.functional.membersinject;
-
-class ChildOfArrayOfParentOfStringArray extends
- MembersInjectGenericParent<MembersInjectGenericParent<String[]>[]> {
-}
diff --git a/javatests/dagger/functional/membersinject/ChildOfPrimitiveIntArray.java b/javatests/dagger/functional/membersinject/ChildOfPrimitiveIntArray.java
deleted file mode 100644
index 154bcff..0000000
--- a/javatests/dagger/functional/membersinject/ChildOfPrimitiveIntArray.java
+++ /dev/null
@@ -1,21 +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.functional.membersinject;
-
-class ChildOfPrimitiveIntArray extends MembersInjectGenericParent<int[]> {
-
-}
diff --git a/javatests/dagger/functional/membersinject/ChildOfStringArray.java b/javatests/dagger/functional/membersinject/ChildOfStringArray.java
deleted file mode 100644
index d8bab7c..0000000
--- a/javatests/dagger/functional/membersinject/ChildOfStringArray.java
+++ /dev/null
@@ -1,21 +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.functional.membersinject;
-
-class ChildOfStringArray extends MembersInjectGenericParent<String[]> {
-
-}
diff --git a/javatests/dagger/functional/membersinject/MembersInjectComponent.java b/javatests/dagger/functional/membersinject/MembersInjectComponent.java
deleted file mode 100644
index ed26113..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectComponent.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.functional.membersinject;
-
-import dagger.Component;
-
-@Component(modules = {MembersInjectModule.class})
-interface MembersInjectComponent {
-
- void inject(ChildOfStringArray subfoo);
- void inject(ChildOfArrayOfParentOfStringArray subfoo);
- void inject(ChildOfPrimitiveIntArray subfoo);
- void inject(RawFrameworkTypes rawFrameworkTypes);
-
-}
diff --git a/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java b/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java
deleted file mode 100644
index 3519348..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java
+++ /dev/null
@@ -1,25 +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.functional.membersinject;
-
-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
deleted file mode 100644
index d60a7d1..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectModule.java
+++ /dev/null
@@ -1,32 +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.functional.membersinject;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-class MembersInjectModule {
-
- @Provides String[] provideStringArray() { return new String[10]; }
-
- @Provides int[] provideIntArray() { return new int[10]; }
-
- @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
deleted file mode 100644
index 0617fd5..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectTest.java
+++ /dev/null
@@ -1,96 +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.functional.membersinject;
-
-import static com.google.common.truth.Truth.assertThat;
-
-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.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MembersInjectTest {
- @Test public void testMembersInject_arrays() {
- MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
-
- ChildOfStringArray childOfStringArray = new ChildOfStringArray();
- component.inject(childOfStringArray);
- }
-
- @Test public void testMembersInject_nestedArrays() {
- MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
-
- ChildOfArrayOfParentOfStringArray childOfArrayOfParentOfStringArray =
- new ChildOfArrayOfParentOfStringArray();
- component.inject(childOfArrayOfParentOfStringArray);
- }
-
- @Test public void testMembersInject_primitives() {
- MembersInjectComponent component = DaggerMembersInjectComponent.builder().build();
-
- ChildOfPrimitiveIntArray childOfPrimitiveIntArray = new ChildOfPrimitiveIntArray();
- component.inject(childOfPrimitiveIntArray);
- }
-
- @Test
- public void testMembersInject_overrides() {
- MembersInjectionVisibilityComponent component =
- DaggerMembersInjectionVisibilityComponent.create();
- AParent aParent = new AParent();
- component.inject(aParent);
- assertThat(aParent.aParentField()).isNotNull();
- assertThat(aParent.aParentMethod()).isNotNull();
-
- BChild aChild = new BChild();
- component.inject(aChild);
- assertThat(aChild.aParentField()).isNotNull();
- assertThat(aChild.aParentMethod()).isNull();
- assertThat(aChild.aChildField()).isNotNull();
- assertThat(aChild.aChildMethod()).isNotNull();
-
- AGrandchild aGrandchild = new AGrandchild();
- component.inject(aGrandchild);
- assertThat(aGrandchild.aParentField()).isNotNull();
- assertThat(aGrandchild.aParentMethod()).isNotNull();
- assertThat(aGrandchild.aChildField()).isNotNull();
- assertThat(aGrandchild.aChildMethod()).isNull();
- assertThat(aGrandchild.aGrandchildField()).isNotNull();
- assertThat(aGrandchild.aGrandchildMethod()).isNotNull();
- }
-
- @Test
- public void testNonRequestedMembersInjector() {
- NonRequestedChild child = new NonRequestedChild();
- Provider<String> provider =
- new Provider<String>() {
- @Override
- public String get() {
- return "field!";
- }
- };
- MembersInjector<NonRequestedChild> injector = new NonRequestedChild_MembersInjector(provider);
- injector.injectMembers(child);
- assertThat(child.t).isEqualTo("field!");
- }
-}
diff --git a/javatests/dagger/functional/membersinject/MembersInjectionOrdering.java b/javatests/dagger/functional/membersinject/MembersInjectionOrdering.java
deleted file mode 100644
index 451e0e3..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectionOrdering.java
+++ /dev/null
@@ -1,64 +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.functional.membersinject;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import javax.inject.Inject;
-
-/**
- * This exhibits a regression case, that albeit weird, is valid according to the JSR 330 spec. JSR
- * 330 specifies a rough ordering by which members should be injected, and it is possible to rely on
- * such ordering. When members injecting {@link Subtype}, field injection is guaranteed to be
- * performed on {@link Base} first. The binding for {@code @FirstToString} in {@link
- * OrderingModule#provideToString()} relies on this ordering, and thus uses the value in {@link
- * Base#first} to satisfy the binding.
- */
-class MembersInjectionOrdering {
- static class Base {
- @Inject First first;
- }
-
- static class Subtype extends Base {
- @Inject String firstToString;
- }
-
- @Module
- static class OrderingModule {
- private final Subtype subtype;
-
- OrderingModule(Subtype subtype) {
- this.subtype = subtype;
- }
-
- @Provides
- String provideToString() {
- return subtype.first.toString();
- }
- }
-
- @Component(modules = OrderingModule.class)
- interface TestComponent {
- void inject(Subtype subtype);
- }
-
- static class First {
- @Inject
- First() {}
- }
-}
diff --git a/javatests/dagger/functional/membersinject/MembersInjectionOrderingTest.java b/javatests/dagger/functional/membersinject/MembersInjectionOrderingTest.java
deleted file mode 100644
index efd5117..0000000
--- a/javatests/dagger/functional/membersinject/MembersInjectionOrderingTest.java
+++ /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.
- */
-
-package dagger.functional.membersinject;
-
-import dagger.functional.membersinject.MembersInjectionOrdering.OrderingModule;
-import dagger.functional.membersinject.MembersInjectionOrdering.Subtype;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MembersInjectionOrderingTest {
- @Test
- public void indirection() {
- Subtype toInject = new Subtype();
- DaggerMembersInjectionOrdering_TestComponent.builder()
- .orderingModule(new OrderingModule(toInject))
- .build()
- .inject(toInject);
- }
-}
diff --git a/javatests/dagger/functional/membersinject/MembersWithSameName.java b/javatests/dagger/functional/membersinject/MembersWithSameName.java
deleted file mode 100644
index 2b06898..0000000
--- a/javatests/dagger/functional/membersinject/MembersWithSameName.java
+++ /dev/null
@@ -1,34 +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.functional.membersinject;
-
-import javax.inject.Inject;
-
-// https://github.com/google/dagger/issues/755
-public class MembersWithSameName {
- @Inject String sameName;
- boolean sameNameStringWasInvoked;
- boolean sameNameObjectWasInvoked;
-
- @Inject void sameName(String sameName) {
- sameNameStringWasInvoked = true;
- }
-
- @Inject void sameName(Object sameName) {
- sameNameObjectWasInvoked = true;
- }
-}
diff --git a/javatests/dagger/functional/membersinject/MembersWithSameNameTest.java b/javatests/dagger/functional/membersinject/MembersWithSameNameTest.java
deleted file mode 100644
index 0f22bf3..0000000
--- a/javatests/dagger/functional/membersinject/MembersWithSameNameTest.java
+++ /dev/null
@@ -1,78 +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.functional.membersinject;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.functional.membersinject.subpackage.ExtendsMembersWithSameName;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-// https://github.com/google/dagger/issues/755
-@RunWith(JUnit4.class)
-public class MembersWithSameNameTest {
- @Test
- public void injectsMaskedMembers() {
- MembersWithSameName membersWithSameName = new MembersWithSameName();
- TestComponent component = DaggerMembersWithSameNameTest_TestComponent.create();
- component.inject(membersWithSameName);
- verifyBaseClassInjection(membersWithSameName);
- }
-
- @Test
- public void subclassInjectsMaskedMembers() {
- ExtendsMembersWithSameName extendsMembersWithSameName = new ExtendsMembersWithSameName();
- TestComponent component = DaggerMembersWithSameNameTest_TestComponent.create();
- component.inject(extendsMembersWithSameName);
- verifyBaseClassInjection(extendsMembersWithSameName);
- verifySubclassInjection(extendsMembersWithSameName);
- }
-
- private void verifyBaseClassInjection(MembersWithSameName membersWithSameName) {
- assertThat(membersWithSameName.sameName).isNotNull();
- assertThat(membersWithSameName.sameNameStringWasInvoked).isTrue();
- assertThat(membersWithSameName.sameNameObjectWasInvoked).isTrue();
- }
-
- private void verifySubclassInjection(ExtendsMembersWithSameName extendsMembersWithSameName) {
- assertThat(extendsMembersWithSameName.sameName()).isNotNull();
- assertThat(extendsMembersWithSameName.sameNameStringWasInvoked()).isTrue();
- assertThat(extendsMembersWithSameName.sameNameObjectWasInvoked()).isTrue();
- }
-
- @Module
- abstract static class TestModule {
- @Provides
- static String provideString() {
- return "";
- }
-
- @Binds
- abstract Object bindObject(String string);
- }
-
- @Component(modules = TestModule.class)
- interface TestComponent {
- void inject(MembersWithSameName membersWithSameName);
- void inject(ExtendsMembersWithSameName extendsMembersWithSameName);
- }
-}
diff --git a/javatests/dagger/functional/membersinject/NonRequestedChild.java b/javatests/dagger/functional/membersinject/NonRequestedChild.java
deleted file mode 100644
index a060473..0000000
--- a/javatests/dagger/functional/membersinject/NonRequestedChild.java
+++ /dev/null
@@ -1,28 +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.functional.membersinject;
-
-import javax.inject.Inject;
-
-/**
- * A class that should not be requested by any component, to ensure that we still generate a members
- * injector for it.
- */
-class NonRequestedChild extends MembersInjectGenericParent<String> {
- @Inject
- NonRequestedChild() {}
-}
diff --git a/javatests/dagger/functional/membersinject/RawFrameworkTypes.java b/javatests/dagger/functional/membersinject/RawFrameworkTypes.java
deleted file mode 100644
index 2180613..0000000
--- a/javatests/dagger/functional/membersinject/RawFrameworkTypes.java
+++ /dev/null
@@ -1,29 +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.functional.membersinject;
-
-import dagger.Lazy;
-import dagger.MembersInjector;
-import javax.inject.Provider;
-
-// https://github.com/google/dagger/issues/419
-@SuppressWarnings({"rawtypes", "unused"})
-class RawFrameworkTypes {
- void nonInjectMethodWithARawProvider(Provider rawProvider) {}
- void nonInjectMethodWithARawLazy(Lazy rawLazy) {}
- void nonInjectMethodWithARawMembersInjector(MembersInjector rawMembersInjector) {}
-}
diff --git a/javatests/dagger/functional/membersinject/subpackage/ExtendsMembersWithSameName.java b/javatests/dagger/functional/membersinject/subpackage/ExtendsMembersWithSameName.java
deleted file mode 100644
index 1eb1b15..0000000
--- a/javatests/dagger/functional/membersinject/subpackage/ExtendsMembersWithSameName.java
+++ /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.
- */
-
-package dagger.functional.membersinject.subpackage;
-
-import dagger.functional.membersinject.MembersWithSameName;
-import javax.inject.Inject;
-
-// https://github.com/google/dagger/issues/755
-public class ExtendsMembersWithSameName extends MembersWithSameName {
- @Inject String sameName;
- private boolean sameNameStringWasInvoked;
- private boolean sameNameObjectWasInvoked;
-
- @Inject void sameName(String sameName) {
- sameNameStringWasInvoked = true;
- }
-
- @Inject void sameName(Object sameName) {
- sameNameObjectWasInvoked = true;
- }
-
- public String sameName() {
- return sameName;
- }
- public boolean sameNameStringWasInvoked() {
- return sameNameStringWasInvoked;
- }
- public boolean sameNameObjectWasInvoked() {
- return sameNameObjectWasInvoked;
- }
-}
diff --git a/javatests/dagger/functional/modules/ModuleIncludesTest.java b/javatests/dagger/functional/modules/ModuleIncludesTest.java
deleted file mode 100644
index 38f7d97..0000000
--- a/javatests/dagger/functional/modules/ModuleIncludesTest.java
+++ /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.
- */
-
-package dagger.functional.modules;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.functional.modules.subpackage.PublicModule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ModuleIncludesTest {
-
- @Component(modules = PublicModule.class)
- interface TestComponent {
- Object object();
- }
-
- @Test
- public void publicModuleIncludingPackagePrivateModuleThatDoesNotRequireInstance() {
- TestComponent component = DaggerModuleIncludesTest_TestComponent.create();
- assertThat(component.object()).isEqualTo("foo42");
- }
-}
diff --git a/javatests/dagger/functional/modules/subpackage/PackagePrivateModule.java b/javatests/dagger/functional/modules/subpackage/PackagePrivateModule.java
deleted file mode 100644
index 66852d7..0000000
--- a/javatests/dagger/functional/modules/subpackage/PackagePrivateModule.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.functional.modules.subpackage;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-abstract class PackagePrivateModule {
- @Binds
- abstract Object bindObject(String string);
-
- @Provides
- static String provideString(int i) {
- return "foo" + i;
- }
-}
diff --git a/javatests/dagger/functional/modules/subpackage/PublicModule.java b/javatests/dagger/functional/modules/subpackage/PublicModule.java
deleted file mode 100644
index 7c5fd29..0000000
--- a/javatests/dagger/functional/modules/subpackage/PublicModule.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.functional.modules.subpackage;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module(includes = PackagePrivateModule.class)
-public abstract class PublicModule {
- @Provides
- static int provideInt() {
- return 42;
- }
-}
diff --git a/javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.java b/javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.java
deleted file mode 100644
index 6256812..0000000
--- a/javatests/dagger/functional/multibindings/BindsInaccessibleMapKey.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.functional.multibindings;
-
-import dagger.Component;
-import dagger.functional.multibindings.subpackage.BindsInaccessibleMapKeyModule;
-import java.util.Map;
-
-// b/73820357
-@Component(modules = BindsInaccessibleMapKeyModule.class)
-interface BindsInaccessibleMapKey {
- Map<Class<?>, Object> mapWithAnInaccessibleMapKey();
-}
diff --git a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java b/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
deleted file mode 100644
index f2b5598..0000000
--- a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
+++ /dev/null
@@ -1,74 +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.functional.multibindings;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.auto.value.AutoAnnotation;
-import dagger.Component;
-import dagger.MapKey;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoMap;
-import java.util.Map;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ComplexMapKeysInDifferentOrderTest {
- @MapKey(unwrapValue = false)
- @interface ComplexMapKey {
- int i();
- int j();
- }
-
- @Module
- interface TestModule {
- @Provides
- @IntoMap
- @ComplexMapKey(i = 1, j = 2)
- static int inOrder() {
- return 3;
- }
-
- @Provides
- @IntoMap
- @ComplexMapKey(j = 4, i = 5)
- static int backwardsOrder() {
- return 6;
- }
- }
-
- @Component(modules = TestModule.class)
- interface TestComponent {
- Map<ComplexMapKey, Integer> map();
- }
-
- @Test
- public void test() {
- Map<ComplexMapKey, Integer> map =
- DaggerComplexMapKeysInDifferentOrderTest_TestComponent.create().map();
- assertThat(map.get(mapKey(1, 2))).isEqualTo(3);
- assertThat(map.get(mapKey(5, 4))).isEqualTo(6);
- }
-
- @AutoAnnotation
- static ComplexMapKey mapKey(int i, int j) {
- return new AutoAnnotation_ComplexMapKeysInDifferentOrderTest_mapKey(i, j);
- }
-}
diff --git a/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java b/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java
deleted file mode 100644
index f188405..0000000
--- a/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java
+++ /dev/null
@@ -1,74 +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.functional.multibindings;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.auto.value.AutoAnnotation;
-import dagger.Component;
-import dagger.MapKey;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoMap;
-import java.util.Map;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class MapKeyWithDefaultTest {
- @MapKey(unwrapValue = false)
- @interface MapKeyWithDefault {
- boolean hasDefault() default true;
- boolean required();
- }
-
- @Module
- interface TestModule {
- @Provides
- @IntoMap
- @MapKeyWithDefault(required = false)
- static int justRequired() {
- return 1;
- }
-
- @Provides
- @IntoMap
- @MapKeyWithDefault(required = false, hasDefault = false)
- static int both() {
- return 2;
- }
- }
-
- @Component(modules = TestModule.class)
- interface TestComponent {
- Map<MapKeyWithDefault, Integer> map();
- }
-
- @Test
- public void test() {
- Map<MapKeyWithDefault, Integer> map = DaggerMapKeyWithDefaultTest_TestComponent.create().map();
- assertThat(map).hasSize(2);
- assertThat(map.get(mapKey(true, false))).isEqualTo(1);
- assertThat(map.get(mapKey(false, false))).isEqualTo(2);
- }
-
- @AutoAnnotation
- static MapKeyWithDefault mapKey(boolean hasDefault, boolean required) {
- return new AutoAnnotation_MapKeyWithDefaultTest_mapKey(hasDefault, required);
- }
-}
diff --git a/javatests/dagger/functional/multibindings/subpackage/BindsInaccessibleMapKeyModule.java b/javatests/dagger/functional/multibindings/subpackage/BindsInaccessibleMapKeyModule.java
deleted file mode 100644
index 62df4ae..0000000
--- a/javatests/dagger/functional/multibindings/subpackage/BindsInaccessibleMapKeyModule.java
+++ /dev/null
@@ -1,35 +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.functional.multibindings.subpackage;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import javax.inject.Inject;
-
-@Module
-public abstract class BindsInaccessibleMapKeyModule {
- @Binds
- @IntoMap
- @ClassKey(Inaccessible.class)
- abstract Object bindInaccessibleMapKey(Inaccessible inaccessible);
-
- static class Inaccessible {
- @Inject Inaccessible() {}
- }
-}
diff --git a/javatests/dagger/functional/multipackage/FooComponent.java b/javatests/dagger/functional/multipackage/FooComponent.java
deleted file mode 100644
index ef5b8d5..0000000
--- a/javatests/dagger/functional/multipackage/FooComponent.java
+++ /dev/null
@@ -1,48 +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.functional.multipackage;
-
-import dagger.Component;
-import dagger.functional.multipackage.a.AModule;
-import dagger.functional.multipackage.a.UsesInaccessible;
-import dagger.functional.multipackage.a.UsesInaccessibleInGenericsOnly;
-import dagger.functional.multipackage.sub.FooChildComponent;
-import java.util.Set;
-
-/**
- * A component that tests the interaction between subcomponents, multiple packages, and
- * multibindings. Specifically, we want:
- * <ul>
- * <li>A set binding with some contributions in the parent component, and some in the subcomponent.
- * <li>The contributions come from different packages, but not the package of either component.
- * <li>The set binding is requested in the subcomponent through a binding from a separate package.
- * <li>No binding in the subcomponent, that's in the subcomponent's package, directly uses any
- * binding from the component's package.
- * </ul>
- */
-// NOTE(beder): Be careful about changing any bindings in either this component or the subcomponent.
-// Even adding a binding might stop this test from testing what it's supposed to test.
-@Component(modules = {AModule.class})
-interface FooComponent {
- Set<String> setOfString();
-
- FooChildComponent fooChildComponent();
-
- UsesInaccessible usesInaccessible();
-
- UsesInaccessibleInGenericsOnly accessibleConstructorUsesInaccessibleInGenericsOnly();
-}
diff --git a/javatests/dagger/functional/multipackage/MembersInjectionVisibilityComponent.java b/javatests/dagger/functional/multipackage/MembersInjectionVisibilityComponent.java
deleted file mode 100644
index 32b9c5e..0000000
--- a/javatests/dagger/functional/multipackage/MembersInjectionVisibilityComponent.java
+++ /dev/null
@@ -1,35 +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.functional.multipackage;
-
-import dagger.Component;
-import dagger.functional.multipackage.a.AGrandchild;
-import dagger.functional.multipackage.a.AModule;
-import dagger.functional.multipackage.a.AParent;
-import dagger.functional.multipackage.b.BChild;
-
-/**
- * A component that tests members injection across packages and subclasses.
- */
-@Component(modules = {AModule.class})
-public interface MembersInjectionVisibilityComponent {
- void inject(AParent aParent);
-
- void inject(BChild aChild);
-
- void inject(AGrandchild aGrandchild);
-}
diff --git a/javatests/dagger/functional/multipackage/MultibindsComponent.java b/javatests/dagger/functional/multipackage/MultibindsComponent.java
deleted file mode 100644
index dbeeed8..0000000
--- a/javatests/dagger/functional/multipackage/MultibindsComponent.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.functional.multipackage;
-
-import dagger.Component;
-import dagger.functional.multipackage.a.AMultibindsModule;
-import dagger.functional.multipackage.a.UsesInaccessible;
-
-/**
- * A component that tests the interaction between multiple packages and {@code @Multibinding}s.
- * Specifically, we want:
- *
- * <ul>
- * <li>A {@code @Multibinding} for an empty set of a type not accessible from this package.
- * <li>A {@code @Multibinding} for an empty map of a type not accessible from this package.
- * <li>A public type that injects the empty set and map of inaccessible objects.
- * </ul>
- */
-@Component(modules = {AMultibindsModule.class})
-interface MultibindsComponent {
- UsesInaccessible usesInaccessible();
-}
diff --git a/javatests/dagger/functional/multipackage/PrimitivesAcrossPackagesComponent.java b/javatests/dagger/functional/multipackage/PrimitivesAcrossPackagesComponent.java
deleted file mode 100644
index 639558f..0000000
--- a/javatests/dagger/functional/multipackage/PrimitivesAcrossPackagesComponent.java
+++ /dev/null
@@ -1,29 +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.functional.multipackage;
-
-import dagger.Component;
-import dagger.functional.multipackage.primitives.PrimitiveAcrossPackagesModule;
-import javax.inject.Provider;
-
-// b/77150738#comment11
-@Component(modules = PrimitiveAcrossPackagesModule.class)
-interface PrimitivesAcrossPackagesComponent {
- boolean primitive();
-
- Provider<Boolean> boxedPrimitive();
-}
diff --git a/javatests/dagger/functional/multipackage/UsesModuleWithInaccessibleConstructor.java b/javatests/dagger/functional/multipackage/UsesModuleWithInaccessibleConstructor.java
deleted file mode 100644
index 7764112..0000000
--- a/javatests/dagger/functional/multipackage/UsesModuleWithInaccessibleConstructor.java
+++ /dev/null
@@ -1,25 +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.functional.multipackage;
-
-import dagger.Component;
-import dagger.functional.multipackage.moduleconstructor.ModuleWithInaccessibleConstructor;
-
-@Component(modules = ModuleWithInaccessibleConstructor.class)
-public interface UsesModuleWithInaccessibleConstructor {
- int i();
-}
diff --git a/javatests/dagger/functional/multipackage/a/AGrandchild.java b/javatests/dagger/functional/multipackage/a/AGrandchild.java
deleted file mode 100644
index ffb03d5..0000000
--- a/javatests/dagger/functional/multipackage/a/AGrandchild.java
+++ /dev/null
@@ -1,52 +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.functional.multipackage.a;
-
-import dagger.functional.multipackage.b.BChild;
-import javax.inject.Inject;
-
-public class AGrandchild extends BChild {
-
- @Inject APackagePrivateObject aGrandchildField;
-
- private APackagePrivateObject aGrandchildMethod;
-
- @Inject
- void aGrandchildMethod(APackagePrivateObject aGrandchildMethod) {
- this.aGrandchildMethod = aGrandchildMethod;
- }
-
- @Override
- @Inject
- protected void aParentMethod(APublicObject aParentMethod) {
- super.aParentMethod(aParentMethod);
- }
-
- @SuppressWarnings("OverridesJavaxInjectableMethod")
- @Override
- protected void aChildMethod(APublicObject aChildMethod) {
- super.aChildMethod(aChildMethod);
- }
-
- public APackagePrivateObject aGrandchildField() {
- return aGrandchildField;
- }
-
- public APackagePrivateObject aGrandchildMethod() {
- return aGrandchildMethod;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/a/AModule.java b/javatests/dagger/functional/multipackage/a/AModule.java
deleted file mode 100644
index 9f6a7c5..0000000
--- a/javatests/dagger/functional/multipackage/a/AModule.java
+++ /dev/null
@@ -1,51 +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.functional.multipackage.a;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.multibindings.StringKey;
-import java.util.HashSet;
-import java.util.Set;
-
-@Module
-public abstract class AModule {
- @Provides
- @IntoSet
- static String provideString() {
- return "a";
- }
-
- @Binds
- @IntoSet
- abstract Inaccessible provideInaccessible(Inaccessible inaccessible);
-
- @Provides
- @ElementsIntoSet
- static Set<Inaccessible> provideSetOfInaccessibles() {
- return new HashSet<>();
- }
-
- @Binds
- @IntoMap
- @StringKey("inaccessible")
- abstract Inaccessible provideInaccessibleToMap(Inaccessible inaccessible);
-}
diff --git a/javatests/dagger/functional/multipackage/a/AMultibindsModule.java b/javatests/dagger/functional/multipackage/a/AMultibindsModule.java
deleted file mode 100644
index bcf28c9..0000000
--- a/javatests/dagger/functional/multipackage/a/AMultibindsModule.java
+++ /dev/null
@@ -1,32 +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.functional.multipackage.a;
-
-import dagger.Module;
-import dagger.multibindings.Multibinds;
-import java.util.Map;
-import java.util.Set;
-
-/** A module that {@code @Multibinds} a set and a map of {@link Inaccessible}. */
-@Module
-public abstract class AMultibindsModule {
- @Multibinds
- abstract Set<Inaccessible> inaccessibleSet();
-
- @Multibinds
- abstract Map<String, Inaccessible> inaccessibleMap();
-}
diff --git a/javatests/dagger/functional/multipackage/a/APackagePrivateObject.java b/javatests/dagger/functional/multipackage/a/APackagePrivateObject.java
deleted file mode 100644
index f674b82..0000000
--- a/javatests/dagger/functional/multipackage/a/APackagePrivateObject.java
+++ /dev/null
@@ -1,25 +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.functional.multipackage.a;
-
-import javax.inject.Inject;
-
-class APackagePrivateObject {
-
- @Inject
- APackagePrivateObject() {}
-}
diff --git a/javatests/dagger/functional/multipackage/a/AParent.java b/javatests/dagger/functional/multipackage/a/AParent.java
deleted file mode 100644
index de99ffd..0000000
--- a/javatests/dagger/functional/multipackage/a/AParent.java
+++ /dev/null
@@ -1,39 +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.functional.multipackage.a;
-
-import javax.inject.Inject;
-
-public class AParent {
-
- @Inject APackagePrivateObject aParentField;
-
- private APublicObject aParentMethod;
-
- @Inject
- protected void aParentMethod(APublicObject aParentMethod) {
- this.aParentMethod = aParentMethod;
- }
-
- public APackagePrivateObject aParentField() {
- return aParentField;
- }
-
- public APublicObject aParentMethod() {
- return aParentMethod;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/a/APublicObject.java b/javatests/dagger/functional/multipackage/a/APublicObject.java
deleted file mode 100644
index 6c85721..0000000
--- a/javatests/dagger/functional/multipackage/a/APublicObject.java
+++ /dev/null
@@ -1,25 +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.functional.multipackage.a;
-
-import javax.inject.Inject;
-
-public class APublicObject {
-
- @Inject
- APublicObject() {}
-}
diff --git a/javatests/dagger/functional/multipackage/a/Inaccessible.java b/javatests/dagger/functional/multipackage/a/Inaccessible.java
deleted file mode 100644
index 30e2861..0000000
--- a/javatests/dagger/functional/multipackage/a/Inaccessible.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.functional.multipackage.a;
-
-import javax.inject.Inject;
-
-final class Inaccessible {
- @Inject Inaccessible() {}
-}
\ No newline at end of file
diff --git a/javatests/dagger/functional/multipackage/a/InaccessibleGeneric.java b/javatests/dagger/functional/multipackage/a/InaccessibleGeneric.java
deleted file mode 100644
index f5da79d..0000000
--- a/javatests/dagger/functional/multipackage/a/InaccessibleGeneric.java
+++ /dev/null
@@ -1,24 +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.functional.multipackage.a;
-
-import javax.inject.Inject;
-
-final class InaccessibleGeneric<T> {
- @Inject
- InaccessibleGeneric() {}
-}
diff --git a/javatests/dagger/functional/multipackage/a/UsesInaccessible.java b/javatests/dagger/functional/multipackage/a/UsesInaccessible.java
deleted file mode 100644
index 7a8ed7f..0000000
--- a/javatests/dagger/functional/multipackage/a/UsesInaccessible.java
+++ /dev/null
@@ -1,31 +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.functional.multipackage.a;
-
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-
-@SuppressWarnings("unused")
-public class UsesInaccessible {
- @Inject
- public UsesInaccessible(
- Inaccessible inaccessible,
- Set<Inaccessible> inaccessibleSet,
- Map<String, Inaccessible> inaccessibleMap,
- InaccessibleGeneric<Integer> inaccessibleGeneric) {}
-}
diff --git a/javatests/dagger/functional/multipackage/a/UsesInaccessibleInGenericsOnly.java b/javatests/dagger/functional/multipackage/a/UsesInaccessibleInGenericsOnly.java
deleted file mode 100644
index a69aa56..0000000
--- a/javatests/dagger/functional/multipackage/a/UsesInaccessibleInGenericsOnly.java
+++ /dev/null
@@ -1,28 +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.functional.multipackage.a;
-
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-
-@SuppressWarnings("unused")
-public class UsesInaccessibleInGenericsOnly {
- @Inject
- public UsesInaccessibleInGenericsOnly(
- Set<Inaccessible> inaccessibleSet, Map<String, Inaccessible> inaccessibleMap) {}
-}
diff --git a/javatests/dagger/functional/multipackage/b/BChild.java b/javatests/dagger/functional/multipackage/b/BChild.java
deleted file mode 100644
index fe5da66..0000000
--- a/javatests/dagger/functional/multipackage/b/BChild.java
+++ /dev/null
@@ -1,47 +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.functional.multipackage.b;
-
-import dagger.functional.multipackage.a.AParent;
-import dagger.functional.multipackage.a.APublicObject;
-import javax.inject.Inject;
-
-public class BChild extends AParent {
-
- @Inject BPackagePrivateObject aChildField;
-
- private APublicObject aChildMethod;
-
- @Inject
- protected void aChildMethod(APublicObject aChildMethod) {
- this.aChildMethod = aChildMethod;
- }
-
- @SuppressWarnings("OverridesJavaxInjectableMethod")
- @Override
- protected void aParentMethod(APublicObject aParentMethod) {
- super.aParentMethod(aParentMethod);
- }
-
- public BPackagePrivateObject aChildField() {
- return aChildField;
- }
-
- public APublicObject aChildMethod() {
- return aChildMethod;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/b/BModule.java b/javatests/dagger/functional/multipackage/b/BModule.java
deleted file mode 100644
index 6edf4bf..0000000
--- a/javatests/dagger/functional/multipackage/b/BModule.java
+++ /dev/null
@@ -1,30 +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.functional.multipackage.b;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-public final class BModule {
- @Provides
- @IntoSet
- static String provideString() {
- return "b";
- }
-}
diff --git a/javatests/dagger/functional/multipackage/b/BPackagePrivateObject.java b/javatests/dagger/functional/multipackage/b/BPackagePrivateObject.java
deleted file mode 100644
index b785a4a..0000000
--- a/javatests/dagger/functional/multipackage/b/BPackagePrivateObject.java
+++ /dev/null
@@ -1,25 +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.functional.multipackage.b;
-
-import javax.inject.Inject;
-
-class BPackagePrivateObject {
-
- @Inject
- BPackagePrivateObject() {}
-}
diff --git a/javatests/dagger/functional/multipackage/c/CModule.java b/javatests/dagger/functional/multipackage/c/CModule.java
deleted file mode 100644
index df257ad..0000000
--- a/javatests/dagger/functional/multipackage/c/CModule.java
+++ /dev/null
@@ -1,30 +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.functional.multipackage.c;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-public final class CModule {
- @Provides
- @IntoSet
- static String provideString() {
- return "c";
- }
-}
diff --git a/javatests/dagger/functional/multipackage/d/DModule.java b/javatests/dagger/functional/multipackage/d/DModule.java
deleted file mode 100644
index c98d647..0000000
--- a/javatests/dagger/functional/multipackage/d/DModule.java
+++ /dev/null
@@ -1,30 +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.functional.multipackage.d;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-public final class DModule {
- @Provides
- @IntoSet
- static String provideString() {
- return "d";
- }
-}
diff --git a/javatests/dagger/functional/multipackage/foo/Foo.java b/javatests/dagger/functional/multipackage/foo/Foo.java
deleted file mode 100644
index 1c06aa5..0000000
--- a/javatests/dagger/functional/multipackage/foo/Foo.java
+++ /dev/null
@@ -1,28 +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.functional.multipackage.foo;
-
-import java.util.Set;
-import javax.inject.Inject;
-
-public final class Foo<T> {
- public final Set<String> strings;
-
- @Inject Foo(Set<String> strings) {
- this.strings = strings;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/grandsub/FooGrandchildComponent.java b/javatests/dagger/functional/multipackage/grandsub/FooGrandchildComponent.java
deleted file mode 100644
index 171b92a..0000000
--- a/javatests/dagger/functional/multipackage/grandsub/FooGrandchildComponent.java
+++ /dev/null
@@ -1,26 +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.functional.multipackage.grandsub;
-
-import dagger.Subcomponent;
-import dagger.functional.multipackage.d.DModule;
-import dagger.functional.multipackage.foo.Foo;
-
-@Subcomponent(modules = DModule.class)
-public interface FooGrandchildComponent {
- Foo<FooGrandchildComponent> foo();
-}
diff --git a/javatests/dagger/functional/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.java b/javatests/dagger/functional/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.java
deleted file mode 100644
index 6ca0074..0000000
--- a/javatests/dagger/functional/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.java
+++ /dev/null
@@ -1,35 +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.functional.multipackage.moduleconstructor;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.Random;
-
-@Module
-public class ModuleWithInaccessibleConstructor {
- private final int i;
-
- /* intentionally package private */ModuleWithInaccessibleConstructor() {
- i = new Random().nextInt();
- }
-
- @Provides
- int i() {
- return i;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/primitives/PrimitiveAcrossPackagesModule.java b/javatests/dagger/functional/multipackage/primitives/PrimitiveAcrossPackagesModule.java
deleted file mode 100644
index 1e6e362..0000000
--- a/javatests/dagger/functional/multipackage/primitives/PrimitiveAcrossPackagesModule.java
+++ /dev/null
@@ -1,29 +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.functional.multipackage.primitives;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public final class PrimitiveAcrossPackagesModule {
- // This method should be package-private so that a proxy method is created
- @Provides
- static boolean primitive() {
- return false;
- }
-}
diff --git a/javatests/dagger/functional/multipackage/sub/FooChildComponent.java b/javatests/dagger/functional/multipackage/sub/FooChildComponent.java
deleted file mode 100644
index b4f1389..0000000
--- a/javatests/dagger/functional/multipackage/sub/FooChildComponent.java
+++ /dev/null
@@ -1,30 +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.functional.multipackage.sub;
-
-import dagger.Subcomponent;
-import dagger.functional.multipackage.b.BModule;
-import dagger.functional.multipackage.c.CModule;
-import dagger.functional.multipackage.foo.Foo;
-import dagger.functional.multipackage.grandsub.FooGrandchildComponent;
-
-@Subcomponent(modules = {BModule.class, CModule.class})
-public interface FooChildComponent {
- Foo<FooChildComponent> foo();
-
- FooGrandchildComponent fooGrandchildComponent();
-}
diff --git a/javatests/dagger/functional/nullables/NullComponent.java b/javatests/dagger/functional/nullables/NullComponent.java
deleted file mode 100644
index 39f0d34..0000000
--- a/javatests/dagger/functional/nullables/NullComponent.java
+++ /dev/null
@@ -1,30 +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.functional.nullables;
-
-import dagger.Component;
-import javax.inject.Provider;
-
-@Component(modules = NullModule.class)
-interface NullComponent {
- NullFoo nullFoo();
- @Nullable String string();
- Provider<String> stringProvider();
- Number number();
- Provider<Number> numberProvider();
- @Nullable Integer integer();
-}
diff --git a/javatests/dagger/functional/nullables/NullComponentWithDependency.java b/javatests/dagger/functional/nullables/NullComponentWithDependency.java
deleted file mode 100644
index dfb4b82..0000000
--- a/javatests/dagger/functional/nullables/NullComponentWithDependency.java
+++ /dev/null
@@ -1,28 +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.functional.nullables;
-
-import dagger.Component;
-import javax.inject.Provider;
-
-@Component(dependencies = NullComponent.class)
-interface NullComponentWithDependency {
- @Nullable String string();
- Provider<String> stringProvider();
- Number number();
- Provider<Number> numberProvider();
-}
diff --git a/javatests/dagger/functional/nullables/NullFoo.java b/javatests/dagger/functional/nullables/NullFoo.java
deleted file mode 100644
index b3f9a67..0000000
--- a/javatests/dagger/functional/nullables/NullFoo.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.functional.nullables;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-class NullFoo {
- final String string;
- final Provider<String> stringProvider;
- final Number number;
- final Provider<Number> numberProvider;
-
- @Inject
- NullFoo(@Nullable String string,
- Provider<String> stringProvider,
- Number number,
- Provider<Number> numberProvider) {
- this.string = string;
- this.stringProvider = stringProvider;
- this.number = number;
- this.numberProvider = numberProvider;
- }
-
- String methodInjectedString;
- Provider<String> methodInjectedStringProvider;
- Number methodInjectedNumber;
- Provider<Number> methodInjectedNumberProvider;
- @Inject void inject(@Nullable String string,
- Provider<String> stringProvider,
- Number number,
- Provider<Number> numberProvider) {
- this.methodInjectedString = string;
- this.methodInjectedStringProvider = stringProvider;
- this.methodInjectedNumber = number;
- this.methodInjectedNumberProvider = numberProvider;
- }
-
- @Nullable @Inject String fieldInjectedString;
- @Inject Provider<String> fieldInjectedStringProvider;
- @Inject Number fieldInjectedNumber;
- @Inject Provider<Number> fieldInjectedNumberProvider;
-}
diff --git a/javatests/dagger/functional/nullables/NullModule.java b/javatests/dagger/functional/nullables/NullModule.java
deleted file mode 100644
index 0219165..0000000
--- a/javatests/dagger/functional/nullables/NullModule.java
+++ /dev/null
@@ -1,46 +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.functional.nullables;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Reusable;
-
-@Module
-class NullModule {
- Number numberValue = null;
- Integer integerCallCount = 0;
-
- @Nullable
- @Provides
- String provideNullableString() {
- return null;
- }
-
- @Provides
- Number provideNumber() {
- return numberValue;
- }
-
- @Nullable
- @Provides
- @Reusable
- Integer provideNullReusableInteger() {
- integerCallCount++;
- return null;
- }
-}
diff --git a/javatests/dagger/functional/nullables/NullabilityTest.java b/javatests/dagger/functional/nullables/NullabilityTest.java
deleted file mode 100644
index 6706ece..0000000
--- a/javatests/dagger/functional/nullables/NullabilityTest.java
+++ /dev/null
@@ -1,136 +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.functional.nullables;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class NullabilityTest {
- @Test public void testNullability_provides() {
- NullModule module = new NullModule();
- NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
-
- // Can't construct NullFoo because it depends on Number, and Number was null.
- try {
- component.nullFoo();
- fail();
- } catch (NullPointerException npe) {
- assertThat(npe)
- .hasMessageThat()
- .isEqualTo("Cannot return null from a non-@Nullable @Provides method");
- }
-
- // set number to non-null so we can create
- module.numberValue = 1;
- NullFoo nullFoo = component.nullFoo();
-
- // Then set it back to null so we can test its providers.
- module.numberValue = null;
- validate(true, nullFoo.string, nullFoo.stringProvider, nullFoo.numberProvider);
- validate(true, nullFoo.methodInjectedString, nullFoo.methodInjectedStringProvider,
- nullFoo.methodInjectedNumberProvider);
- validate(true, nullFoo.fieldInjectedString, nullFoo.fieldInjectedStringProvider,
- nullFoo.fieldInjectedNumberProvider);
- }
-
- @Test public void testNullability_reusuable() {
- NullModule module = new NullModule();
- NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
-
- // Test that the @Nullable @Reusuable binding is cached properly even when the value is null.
- assertThat(module.integerCallCount).isEqualTo(0);
- assertThat(component.integer()).isNull();
- assertThat(module.integerCallCount).isEqualTo(1);
- assertThat(component.integer()).isNull();
- assertThat(module.integerCallCount).isEqualTo(1);
- }
-
- @Test public void testNullability_components() {
- NullComponent nullComponent = new NullComponent() {
- @Override public Provider<String> stringProvider() {
- return new Provider<String>() {
- @Override public String get() {
- return null;
- }
- };
- }
-
- @Override public String string() {
- return null;
- }
-
- @Override public Provider<Number> numberProvider() {
- return new Provider<Number>() {
- @Override public Number get() {
- return null;
- }
- };
- }
-
- @Override public Number number() {
- return null;
- }
-
- @Override public NullFoo nullFoo() {
- return null;
- }
-
- @Override public Integer integer() {
- return null;
- }
- };
- NullComponentWithDependency component =
- DaggerNullComponentWithDependency.builder().nullComponent(nullComponent).build();
- validate(false, component.string(), component.stringProvider(), component.numberProvider());
-
- // Also validate that the component's number() method fails
- try {
- component.number();
- fail();
- } catch (NullPointerException npe) {
- assertThat(npe)
- .hasMessageThat()
- .isEqualTo("Cannot return null from a non-@Nullable component method");
- }
- }
-
- private void validate(boolean fromProvides,
- String string,
- Provider<String> stringProvider,
- Provider<Number> numberProvider) {
- assertThat(string).isNull();
- assertThat(numberProvider).isNotNull();
- try {
- numberProvider.get();
- fail();
- } catch (NullPointerException npe) {
- assertThat(npe)
- .hasMessageThat()
- .isEqualTo(
- "Cannot return null from a non-@Nullable "
- + (fromProvides ? "@Provides" : "component")
- + " method");
- }
- assertThat(stringProvider.get()).isNull();
- }
-}
diff --git a/javatests/dagger/functional/nullables/Nullable.java b/javatests/dagger/functional/nullables/Nullable.java
deleted file mode 100644
index cbfb98a..0000000
--- a/javatests/dagger/functional/nullables/Nullable.java
+++ /dev/null
@@ -1,19 +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.functional.nullables;
-
-@interface Nullable {}
diff --git a/javatests/dagger/functional/producers/BUILD b/javatests/dagger/functional/producers/BUILD
deleted file mode 100644
index 36c9701..0000000
--- a/javatests/dagger/functional/producers/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:
-# Functional tests for Dagger Producers
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
- "SOURCE_7_TARGET_7",
-)
-load("//:test_defs.bzl", "GenJavaTests")
-
-GenJavaTests(
- name = "producers-functional-tests",
- srcs = glob(["**/*.java"]),
- javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "//:producers_with_compiler",
- "@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",
- ],
-)
-
-test_suite(name = "AllTests")
diff --git a/javatests/dagger/functional/producers/DependedComponent.java b/javatests/dagger/functional/producers/DependedComponent.java
deleted file mode 100644
index 9a4947a..0000000
--- a/javatests/dagger/functional/producers/DependedComponent.java
+++ /dev/null
@@ -1,25 +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.functional.producers;
-
-import dagger.Component;
-
-@Component(modules = DependedModule.class)
-interface DependedComponent {
- String getGreeting();
-}
-
diff --git a/javatests/dagger/functional/producers/DependedModule.java b/javatests/dagger/functional/producers/DependedModule.java
deleted file mode 100644
index 89ca4fc..0000000
--- a/javatests/dagger/functional/producers/DependedModule.java
+++ /dev/null
@@ -1,28 +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.functional.producers;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class DependedModule {
- @Provides
- String provideGreeting() {
- return "Hello world!";
- }
-}
diff --git a/javatests/dagger/functional/producers/DependedProducerModule.java b/javatests/dagger/functional/producers/DependedProducerModule.java
deleted file mode 100644
index c25d4e8..0000000
--- a/javatests/dagger/functional/producers/DependedProducerModule.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.functional.producers;
-
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-@ProducerModule
-final class DependedProducerModule {
-
- @Produces
- int produceNumberOfGreetings() {
- return 2;
- }
-}
diff --git a/javatests/dagger/functional/producers/DependedProductionComponent.java b/javatests/dagger/functional/producers/DependedProductionComponent.java
deleted file mode 100644
index d5ebc4f..0000000
--- a/javatests/dagger/functional/producers/DependedProductionComponent.java
+++ /dev/null
@@ -1,26 +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.functional.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProductionComponent;
-
-@ProductionComponent(modules = {ExecutorModule.class, DependedProducerModule.class})
-interface DependedProductionComponent {
- ListenableFuture<Integer> numGreetings();
-}
-
diff --git a/javatests/dagger/functional/producers/DependentComponent.java b/javatests/dagger/functional/producers/DependentComponent.java
deleted file mode 100644
index 364676c..0000000
--- a/javatests/dagger/functional/producers/DependentComponent.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.functional.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProductionComponent;
-import java.util.List;
-
-@ProductionComponent(
- modules = {ExecutorModule.class, DependentProducerModule.class},
- dependencies = {DependedComponent.class, DependedProductionComponent.class}
-)
-interface DependentComponent {
- ListenableFuture<List<String>> greetings();
-}
diff --git a/javatests/dagger/functional/producers/DependentProducerModule.java b/javatests/dagger/functional/producers/DependentProducerModule.java
deleted file mode 100644
index 56b66f5..0000000
--- a/javatests/dagger/functional/producers/DependentProducerModule.java
+++ /dev/null
@@ -1,35 +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.functional.producers;
-
-import com.google.common.base.Ascii;
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.util.List;
-
-@ProducerModule
-final class DependentProducerModule {
- @Produces
- ListenableFuture<List<String>> greetings(Integer numGreetings, String greeting) {
- List<String> greetings = ImmutableList.of(
- String.valueOf(numGreetings), greeting, Ascii.toUpperCase(greeting));
- return Futures.immediateFuture(greetings);
- }
-}
diff --git a/javatests/dagger/functional/producers/DependentTest.java b/javatests/dagger/functional/producers/DependentTest.java
deleted file mode 100644
index 920d753..0000000
--- a/javatests/dagger/functional/producers/DependentTest.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.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 org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DependentTest {
- @Test public void dependentComponent() throws Exception {
- DependentComponent dependentComponent =
- DaggerDependentComponent.builder()
- .dependedProductionComponent(DaggerDependedProductionComponent.create())
- .dependedComponent(DaggerDependedComponent.create())
- .build();
- assertThat(dependentComponent).isNotNull();
- assertThat(dependentComponent.greetings().get()).containsExactly(
- "2", "Hello world!", "HELLO WORLD!");
- }
-
- @Test public void reuseBuilderWithDependentComponent() throws Exception {
- DaggerDependentComponent.Builder dependentComponentBuilder = DaggerDependentComponent.builder();
-
- DependentComponent componentUsingComponents =
- dependentComponentBuilder
- .dependedProductionComponent(DaggerDependedProductionComponent.create())
- .dependedComponent(DaggerDependedComponent.create())
- .build();
-
- DependentComponent componentUsingJavaImpls = dependentComponentBuilder
- .dependedProductionComponent(new DependedProductionComponent() {
- @Override public ListenableFuture<Integer> numGreetings() {
- return Futures.immediateFuture(3);
- }
- })
- .dependedComponent(new DependedComponent() {
- @Override public String getGreeting() {
- return "Goodbye world!";
- }
- })
- .build();
-
- assertThat(componentUsingJavaImpls.greetings().get()).containsExactly(
- "3", "Goodbye world!", "GOODBYE WORLD!");
- assertThat(componentUsingComponents.greetings().get()).containsExactly(
- "2", "Hello world!", "HELLO WORLD!");
-
- }
-}
diff --git a/javatests/dagger/functional/producers/ExecutorModule.java b/javatests/dagger/functional/producers/ExecutorModule.java
deleted file mode 100644
index 5f8bfbf..0000000
--- a/javatests/dagger/functional/producers/ExecutorModule.java
+++ /dev/null
@@ -1,46 +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.functional.producers;
-
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.Module;
-import dagger.Provides;
-import dagger.producers.Production;
-import java.util.concurrent.Executor;
-
-/**
- * A module that provides an optionally user-defined executor for a production component, defaulting
- * to the direct executor.
- */
-@Module
-public final class ExecutorModule {
- private final Executor executor;
-
- public ExecutorModule() {
- this(MoreExecutors.directExecutor());
- }
-
- public ExecutorModule(Executor executor) {
- this.executor = executor;
- }
-
- @Provides
- @Production
- Executor executor() {
- return executor;
- }
-}
diff --git a/javatests/dagger/functional/producers/GenericComponent.java b/javatests/dagger/functional/producers/GenericComponent.java
deleted file mode 100644
index 775ac2a..0000000
--- a/javatests/dagger/functional/producers/GenericComponent.java
+++ /dev/null
@@ -1,50 +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.functional.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.GenericComponent.NongenericModule;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-import java.util.Arrays;
-import java.util.List;
-
-@ProductionComponent(modules = {ExecutorModule.class, NongenericModule.class})
-interface GenericComponent {
-
- ListenableFuture<List<String>> list(); // b/71595104
-
- // b/71595104
- @ProducerModule
- abstract class GenericModule<T> {
-
- @Produces
- List<T> list(T t, String string) {
- return Arrays.asList(t);
- }
- }
-
- // b/71595104
- @ProducerModule
- class NongenericModule extends GenericModule<String> {
- @Produces
- static String string() {
- return "string";
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/ProducerFactoryTest.java b/javatests/dagger/functional/producers/ProducerFactoryTest.java
deleted file mode 100644
index c85e342..0000000
--- a/javatests/dagger/functional/producers/ProducerFactoryTest.java
+++ /dev/null
@@ -1,203 +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.functional.producers;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.when;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
-import dagger.producers.Producer;
-import dagger.producers.internal.AbstractProducer;
-import dagger.producers.internal.CancellableProducer;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import javax.inject.Provider;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-public class ProducerFactoryTest {
- @Mock private ProductionComponentMonitor componentMonitor;
- private ProducerMonitor monitor;
- private Provider<Executor> executorProvider;
- private Provider<ProductionComponentMonitor> componentMonitorProvider;
-
- @Before
- public void setUpMocks() {
- MockitoAnnotations.initMocks(this);
- monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
- when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
- // TODO(beder): Use Providers.of when available.
- executorProvider =
- new Provider<Executor>() {
- @Override
- public Executor get() {
- return MoreExecutors.directExecutor();
- }
- };
- componentMonitorProvider =
- new Provider<ProductionComponentMonitor>() {
- @Override
- public ProductionComponentMonitor get() {
- return componentMonitor;
- }
- };
- }
-
- @Test
- public void noArgMethod() throws Exception {
- ProducerToken token = ProducerToken.create(SimpleProducerModule_StrFactory.class);
- Producer<String> producer =
- SimpleProducerModule_StrFactory.create(executorProvider, componentMonitorProvider);
- assertThat(producer.get().get()).isEqualTo("str");
- InOrder order = inOrder(componentMonitor, monitor);
- order.verify(componentMonitor).producerMonitorFor(token);
- order.verify(monitor).methodStarting();
- order.verify(monitor).methodFinished();
- order.verify(monitor).succeeded("str");
- order.verifyNoMoreInteractions();
- }
-
- @Test
- public void singleArgMethod() throws Exception {
- SettableFuture<Integer> intFuture = SettableFuture.create();
- CancellableProducer<Integer> intProducer = producerOfFuture(intFuture);
- Producer<String> producer =
- SimpleProducerModule_StrWithArgFactory.create(
- executorProvider, componentMonitorProvider, intProducer);
- assertThat(producer.get().isDone()).isFalse();
- intFuture.set(42);
- assertThat(producer.get().get()).isEqualTo("str with arg");
- }
-
- @Test
- public void successMonitor() throws Exception {
- ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
-
- SettableFuture<String> strFuture = SettableFuture.create();
- @SuppressWarnings("FutureReturnValueIgnored")
- SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
- CancellableProducer<SettableFuture<String>> strFutureProducer =
- producerOfFuture(strFutureFuture);
- Producer<String> producer =
- SimpleProducerModule_SettableFutureStrFactory.create(
- executorProvider, componentMonitorProvider, strFutureProducer);
- assertThat(producer.get().isDone()).isFalse();
-
- InOrder order = inOrder(componentMonitor, monitor);
- order.verify(componentMonitor).producerMonitorFor(token);
-
- strFutureFuture.set(strFuture);
- order.verify(monitor).methodStarting();
- order.verify(monitor).methodFinished();
- assertThat(producer.get().isDone()).isFalse();
-
- strFuture.set("monkey");
- assertThat(producer.get().get()).isEqualTo("monkey");
- order.verify(monitor).succeeded("monkey");
-
- order.verifyNoMoreInteractions();
- }
-
- @Test
- public void failureMonitor() throws Exception {
- ProducerToken token = ProducerToken.create(SimpleProducerModule_SettableFutureStrFactory.class);
-
- SettableFuture<String> strFuture = SettableFuture.create();
- @SuppressWarnings("FutureReturnValueIgnored")
- SettableFuture<SettableFuture<String>> strFutureFuture = SettableFuture.create();
- CancellableProducer<SettableFuture<String>> strFutureProducer =
- producerOfFuture(strFutureFuture);
- Producer<String> producer =
- SimpleProducerModule_SettableFutureStrFactory.create(
- executorProvider, componentMonitorProvider, strFutureProducer);
- assertThat(producer.get().isDone()).isFalse();
-
- InOrder order = inOrder(componentMonitor, monitor);
- order.verify(componentMonitor).producerMonitorFor(token);
-
- strFutureFuture.set(strFuture);
- order.verify(monitor).methodStarting();
- order.verify(monitor).methodFinished();
- assertThat(producer.get().isDone()).isFalse();
-
- Throwable t = new RuntimeException("monkey");
- strFuture.setException(t);
- try {
- producer.get().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isSameInstanceAs(t);
- order.verify(monitor).failed(t);
- }
-
- order.verifyNoMoreInteractions();
- }
-
- @Test
- public void failureMonitorDueToThrowingProducer() throws Exception {
- ProducerToken token = ProducerToken.create(SimpleProducerModule_ThrowingProducerFactory.class);
-
- Producer<String> producer =
- SimpleProducerModule_ThrowingProducerFactory.create(
- executorProvider, componentMonitorProvider);
- assertThat(producer.get().isDone()).isTrue();
-
- InOrder order = inOrder(componentMonitor, monitor);
- order.verify(componentMonitor).producerMonitorFor(token);
-
- order.verify(monitor).methodStarting();
- order.verify(monitor).methodFinished();
-
- try {
- producer.get().get();
- fail();
- } catch (ExecutionException e) {
- order.verify(monitor).failed(e.getCause());
- }
-
- order.verifyNoMoreInteractions();
- }
-
- @Test(expected = NullPointerException.class)
- public void nullComponentMonitorProvider() throws Exception {
- SimpleProducerModule_StrFactory.create(executorProvider, null);
- }
-
- private static <T> CancellableProducer<T> producerOfFuture(final ListenableFuture<T> future) {
- return new AbstractProducer<T>() {
- @Override
- public ListenableFuture<T> compute() {
- return future;
- }
- };
- }
-}
diff --git a/javatests/dagger/functional/producers/ProvidesInProducerModule.java b/javatests/dagger/functional/producers/ProvidesInProducerModule.java
deleted file mode 100644
index 6e3b41f..0000000
--- a/javatests/dagger/functional/producers/ProvidesInProducerModule.java
+++ /dev/null
@@ -1,47 +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.functional.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.Provides;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import java.util.concurrent.Executor;
-
-final class ProvidesInProducerModule {
- @ProducerModule
- static class OnlyModule {
- @Provides
- @Production
- static Executor provideExecutor() {
- return MoreExecutors.directExecutor();
- }
-
- @Produces
- static String produceString() {
- return "produced";
- }
- }
-
- @ProductionComponent(modules = OnlyModule.class)
- interface C {
- ListenableFuture<String> string();
- }
-}
diff --git a/javatests/dagger/functional/producers/Request.java b/javatests/dagger/functional/producers/Request.java
deleted file mode 100644
index d4020c8..0000000
--- a/javatests/dagger/functional/producers/Request.java
+++ /dev/null
@@ -1,32 +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.functional.producers;
-
-import javax.inject.Inject;
-
-final class Request {
- private final String name;
-
- @Inject
- Request() {
- this.name = "Request";
- }
-
- String name() {
- return this.name;
- }
-}
diff --git a/javatests/dagger/functional/producers/Response.java b/javatests/dagger/functional/producers/Response.java
deleted file mode 100644
index ca5c0c2..0000000
--- a/javatests/dagger/functional/producers/Response.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.functional.producers;
-
-final class Response {
- private final String data;
-
- Response(String data) {
- this.data = data;
- }
-
- String data() {
- return this.data;
- }
-}
diff --git a/javatests/dagger/functional/producers/ResponseModule.java b/javatests/dagger/functional/producers/ResponseModule.java
deleted file mode 100644
index 9a5e25d..0000000
--- a/javatests/dagger/functional/producers/ResponseModule.java
+++ /dev/null
@@ -1,28 +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.functional.producers;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class ResponseModule {
- @Provides
- static int requestNumber() {
- return 5;
- }
-}
diff --git a/javatests/dagger/functional/producers/ResponseProducerModule.java b/javatests/dagger/functional/producers/ResponseProducerModule.java
deleted file mode 100644
index 7b76ae2..0000000
--- a/javatests/dagger/functional/producers/ResponseProducerModule.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.functional.producers;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.Lazy;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-@ProducerModule(includes = ResponseModule.class)
-final class ResponseProducerModule {
- @Qualifier
- @interface RequestsProducerAndProduced {}
-
- @Produces
- static ListenableFuture<String> greeting() {
- return Futures.immediateFuture("Hello");
- }
-
- @Produces
- @RequestsProducerAndProduced
- static ListenableFuture<String> intermediateGreeting(
- // TODO(beder): Allow Producer and Provider of the same type (which would force the binding
- // to be a provision binding), and add validation for that.
- @SuppressWarnings("unused") String greeting,
- Producer<String> greetingProducer,
- @SuppressWarnings("unused") Produced<String> greetingProduced,
- @SuppressWarnings("unused") Provider<Integer> requestNumberProvider,
- @SuppressWarnings("unused") Lazy<Integer> requestNumberLazy) {
- return greetingProducer.get();
- }
-
- @Produces
- static Response response(
- @RequestsProducerAndProduced String greeting, Request request, int requestNumber) {
- return new Response(String.format("%s, %s #%d!", greeting, request.name(), requestNumber));
- }
-}
diff --git a/javatests/dagger/functional/producers/SimpleComponent.java b/javatests/dagger/functional/producers/SimpleComponent.java
deleted file mode 100644
index 4b0af7f..0000000
--- a/javatests/dagger/functional/producers/SimpleComponent.java
+++ /dev/null
@@ -1,25 +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.functional.producers;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProductionComponent;
-
-@ProductionComponent(modules = {ExecutorModule.class, ResponseProducerModule.class})
-interface SimpleComponent {
- ListenableFuture<Response> response();
-}
diff --git a/javatests/dagger/functional/producers/SimpleProducerModule.java b/javatests/dagger/functional/producers/SimpleProducerModule.java
deleted file mode 100644
index b0c523d..0000000
--- a/javatests/dagger/functional/producers/SimpleProducerModule.java
+++ /dev/null
@@ -1,281 +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.functional.producers;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import dagger.Lazy;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoSet;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.io.IOException;
-import java.util.Set;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-/**
- * A module that contains various signatures of produces methods. This is not used in any
- * components.
- */
-@ProducerModule
-final class SimpleProducerModule {
- @Qualifier @interface Qual {
- int value();
- }
-
- // Unique bindings.
-
- @Produces
- @Qual(-2)
- static ListenableFuture<String> throwingProducer() {
- throw new RuntimeException("monkey");
- }
-
- @Produces
- @Qual(-1)
- static ListenableFuture<String> settableFutureStr(SettableFuture<String> future) {
- return future;
- }
-
- @Produces
- @Qual(0)
- static String str() {
- return "str";
- }
-
- @Produces
- @Qual(1)
- static ListenableFuture<String> futureStr() {
- return Futures.immediateFuture("future str");
- }
-
- @Produces
- @Qual(2)
- static String strWithArg(@SuppressWarnings("unused") int i) {
- return "str with arg";
- }
-
- @Produces
- @Qual(3)
- static ListenableFuture<String> futureStrWithArg(@SuppressWarnings("unused") int i) {
- return Futures.immediateFuture("future str with arg");
- }
-
- @Produces
- @Qual(4)
- @SuppressWarnings("unused") // unthrown exception for test
- static String strThrowingException() throws IOException {
- return "str throwing exception";
- }
-
- @Produces
- @Qual(5)
- @SuppressWarnings("unused") // unthrown exception for test
- static ListenableFuture<String> futureStrThrowingException() throws IOException {
- return Futures.immediateFuture("future str throwing exception");
- }
-
- @Produces
- @Qual(6)
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static String strWithArgThrowingException(int i) throws IOException {
- return "str with arg throwing exception";
- }
-
- @Produces
- @Qual(7)
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static ListenableFuture<String> futureStrWithArgThrowingException(int i) throws IOException {
- return Futures.immediateFuture("future str with arg throwing exception");
- }
-
- @Produces
- @Qual(8)
- static String strWithArgs(
- @SuppressWarnings("unused") int i,
- @SuppressWarnings("unused") Produced<Double> b,
- @SuppressWarnings("unused") Producer<Object> c,
- @SuppressWarnings("unused") Provider<Boolean> d) {
- return "str with args";
- }
-
- @Produces
- @Qual(9)
- @SuppressWarnings("unused") // unthrown exception for test, unused parameters for test
- static String strWithArgsThrowingException(
- int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
- return "str with args throwing exception";
- }
-
- @Produces
- @Qual(10)
- static ListenableFuture<String> futureStrWithArgs(
- @SuppressWarnings("unused") int i,
- @SuppressWarnings("unused") Produced<Double> b,
- @SuppressWarnings("unused") Producer<Object> c,
- @SuppressWarnings("unused") Provider<Boolean> d) {
- return Futures.immediateFuture("future str with args");
- }
-
- @Produces
- @Qual(11)
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static ListenableFuture<String> futureStrWithArgsThrowingException(
- int i, Produced<Double> b, Producer<Object> c, Provider<Boolean> d) throws IOException {
- return Futures.immediateFuture("str with args throwing exception");
- }
-
- @Produces
- @Qual(12)
- static String strWithFrameworkTypeArgs(
- @SuppressWarnings("unused") @Qual(1) int i,
- @SuppressWarnings("unused") @Qual(1) Provider<Integer> iProvider,
- @SuppressWarnings("unused") @Qual(1) Lazy<Integer> iLazy,
- @SuppressWarnings("unused") @Qual(2) int j,
- @SuppressWarnings("unused") @Qual(2) Produced<Integer> jProduced,
- @SuppressWarnings("unused") @Qual(2) Producer<Integer> jProducer,
- @SuppressWarnings("unused") @Qual(3) Produced<Integer> kProduced,
- @SuppressWarnings("unused") @Qual(3) Producer<Integer> kProducer) {
- return "str with framework type args";
- }
-
- // Set bindings.
-
- @Produces
- @IntoSet
- static String setOfStrElement() {
- return "set of str element";
- }
-
- @Produces
- @IntoSet
- @SuppressWarnings("unused") // unthrown exception for test
- static String setOfStrElementThrowingException() throws IOException {
- return "set of str element throwing exception";
- }
-
- @Produces
- @IntoSet
- static ListenableFuture<String> setOfStrFutureElement() {
- return Futures.immediateFuture("set of str element");
- }
-
- @Produces
- @IntoSet
- @SuppressWarnings("unused") // unthrown exception for test
- static ListenableFuture<String> setOfStrFutureElementThrowingException() throws IOException {
- return Futures.immediateFuture("set of str element throwing exception");
- }
-
- @Produces
- @IntoSet
- static String setOfStrElementWithArg(@SuppressWarnings("unused") int i) {
- return "set of str element with arg";
- }
-
- @Produces
- @IntoSet
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static String setOfStrElementWithArgThrowingException(int i) throws IOException {
- return "set of str element with arg throwing exception";
- }
-
- @Produces
- @IntoSet
- static ListenableFuture<String> setOfStrFutureElementWithArg(@SuppressWarnings("unused") int i) {
- return Futures.immediateFuture("set of str element with arg");
- }
-
- @Produces
- @IntoSet
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static ListenableFuture<String> setOfStrFutureElementWithArgThrowingException(int i)
- throws IOException {
- return Futures.immediateFuture("set of str element with arg throwing exception");
- }
-
- @Produces
- @ElementsIntoSet
- static Set<String> setOfStrValues() {
- return ImmutableSet.of("set of str 1", "set of str 2");
- }
-
- @Produces
- @ElementsIntoSet
- @SuppressWarnings("unused") // unthrown exception for test
- static Set<String> setOfStrValuesThrowingException() throws IOException {
- return ImmutableSet.of("set of str 1", "set of str 2 throwing exception");
- }
-
- @Produces
- @ElementsIntoSet
- static ListenableFuture<Set<String>> setOfStrFutureValues() {
- return Futures.<Set<String>>immediateFuture(ImmutableSet.of("set of str 1", "set of str 2"));
- }
-
- @Produces
- @ElementsIntoSet
- @SuppressWarnings("unused") // unthrown exception for test
- static ListenableFuture<Set<String>> setOfStrFutureValuesThrowingException() throws IOException {
- return Futures.<Set<String>>immediateFuture(
- ImmutableSet.of("set of str 1", "set of str 2 throwing exception"));
- }
-
- @Produces
- @ElementsIntoSet
- static Set<String> setOfStrValuesWithArg(@SuppressWarnings("unused") int i) {
- return ImmutableSet.of("set of str with arg 1", "set of str with arg 2");
- }
-
- @Produces
- @ElementsIntoSet
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static Set<String> setOfStrValuesWithArgThrowingException(int i) throws IOException {
- return ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception");
- }
-
- @Produces
- @ElementsIntoSet
- static ListenableFuture<Set<String>> setOfStrFutureValuesWithArg(
- @SuppressWarnings("unused") int i) {
- return Futures.<Set<String>>immediateFuture(
- ImmutableSet.of("set of str with arg 1", "set of str with arg 2"));
- }
-
- @Produces
- @ElementsIntoSet
- @SuppressWarnings("unused") // unthrown exception for test, unused parameter for test
- static ListenableFuture<Set<String>> setOfStrFutureValuesWithArgThrowingException(int i)
- throws IOException {
- return Futures.<Set<String>>immediateFuture(
- ImmutableSet.of("set of str with arg 1", "set of str with arg 2 throwing exception"));
- }
-
- /**
- * A binding method that might result in a generated factory with conflicting field and parameter
- * names.
- */
- @Produces
- static Object object(int foo, Provider<String> fooProvider) {
- return foo + fooProvider.get();
- }
-}
diff --git a/javatests/dagger/functional/producers/SimpleTest.java b/javatests/dagger/functional/producers/SimpleTest.java
deleted file mode 100644
index e20d098..0000000
--- a/javatests/dagger/functional/producers/SimpleTest.java
+++ /dev/null
@@ -1,32 +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.functional.producers;
-
-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 SimpleTest {
- @Test public void testSimpleComponent() throws Exception {
- SimpleComponent simpleComponent = DaggerSimpleComponent.create();
- assertThat(simpleComponent).isNotNull();
- assertThat(simpleComponent.response().get().data()).isEqualTo("Hello, Request #5!");
- }
-}
diff --git a/javatests/dagger/functional/producers/aot/ProducesMethodShadowsInjectConstructorTest.java b/javatests/dagger/functional/producers/aot/ProducesMethodShadowsInjectConstructorTest.java
deleted file mode 100644
index ef37df2..0000000
--- a/javatests/dagger/functional/producers/aot/ProducesMethodShadowsInjectConstructorTest.java
+++ /dev/null
@@ -1,118 +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.producers.aot;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth8.assertThat;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.BindsOptionalOf;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import javax.inject.Inject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ProducesMethodShadowsInjectConstructorTest {
- static class Multibound {}
- static class Maybe {}
-
- static class HasInjectConstructor {
- @Inject HasInjectConstructor() {}
- }
-
- static class DependsOnShadowingProducer {}
-
- @ProducerModule
- abstract static class LeafModule {
- @Produces
- static DependsOnShadowingProducer dependsOnShadowingProducer(
- // When viewed just within the leaf, this will resolve HasInjectConstructor to the @Inject
- // constructor (and will receive a producerFromProvider), but when viewed within an ancestor
- // that defines a @Produces method for HasInjectConstructor, the binding will be a regular
- // Producer
- HasInjectConstructor hasInjectConstructor,
- Optional<Maybe> maybe) {
- return new DependsOnShadowingProducer();
- }
-
- @Provides
- @IntoSet
- static Multibound provisionContribution() {
- return new Multibound();
- }
-
- @BindsOptionalOf
- abstract Maybe maybe();
- }
-
- @ProductionSubcomponent(modules = LeafModule.class)
- interface Leaf {
- ListenableFuture<DependsOnShadowingProducer> dependsOnShadowingProducer();
- ListenableFuture<Set<Multibound>> shadowedProvisionMultibinding();
- ListenableFuture<Optional<Maybe>> emptyProvisionBindingToPresentProductionBinding();
- }
-
- @ProducerModule
- static class RootModule {
- @Produces
- static HasInjectConstructor shadowInjectConstructor() {
- return new HasInjectConstructor();
- }
-
- @Produces
- @IntoSet
- static Multibound productionContribution() {
- return new Multibound();
- }
-
- @Provides
- @Production
- static Executor executor() {
- return MoreExecutors.directExecutor();
- }
-
- @Produces
- static Maybe presentMaybeInParent() {
- return new Maybe();
- }
- }
-
- @ProductionComponent(modules = RootModule.class)
- interface Root {
- Leaf leaf();
- }
-
- @Test
- public void shadowedInjectConstructorDoesNotCauseClassCast() throws Exception {
- Leaf leaf = DaggerProducesMethodShadowsInjectConstructorTest_Root.create().leaf();
- leaf.dependsOnShadowingProducer().get();
- assertThat(leaf.shadowedProvisionMultibinding().get()).hasSize(2);
- assertThat(leaf.emptyProvisionBindingToPresentProductionBinding().get()).isPresent();
- }
-}
diff --git a/javatests/dagger/functional/producers/badexecutor/BadExecutorTest.java b/javatests/dagger/functional/producers/badexecutor/BadExecutorTest.java
deleted file mode 100644
index e8fb3c5..0000000
--- a/javatests/dagger/functional/producers/badexecutor/BadExecutorTest.java
+++ /dev/null
@@ -1,91 +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.functional.producers.badexecutor;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.functional.producers.ExecutorModule;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.RejectedExecutionException;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** This test verifies behavior when the executor throws {@link RejectedExecutionException}. */
-@RunWith(JUnit4.class)
-public final class BadExecutorTest {
- private SimpleComponent component;
-
- @Before
- public void setUpComponent() {
- ComponentDependency dependency =
- new ComponentDependency() {
- @Override
- public ListenableFuture<Double> doubleDep() {
- return Futures.immediateFuture(42.0);
- }
- };
- ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService();
- component =
- DaggerSimpleComponent.builder()
- .executorModule(new ExecutorModule(executorService))
- .componentDependency(dependency)
- .build();
- executorService.shutdown();
- }
-
- @Test
- public void rejectNoArgMethod() throws Exception {
- try {
- component.noArgStr().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(RejectedExecutionException.class);
- }
- }
-
- @Test
- public void rejectSingleArgMethod() throws Exception {
- try {
- component.singleArgInt().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(RejectedExecutionException.class);
- }
- }
-
- @Test
- public void rejectSingleArgFromComponentDepMethod() throws Exception {
- try {
- component.singleArgBool().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(RejectedExecutionException.class);
- }
- }
-
- @Test
- public void doNotRejectComponentDepMethod() throws Exception {
- assertThat(component.doubleDep().get()).isEqualTo(42.0);
- }
-}
diff --git a/javatests/dagger/functional/producers/badexecutor/ComponentDependency.java b/javatests/dagger/functional/producers/badexecutor/ComponentDependency.java
deleted file mode 100644
index 97974e5..0000000
--- a/javatests/dagger/functional/producers/badexecutor/ComponentDependency.java
+++ /dev/null
@@ -1,23 +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.functional.producers.badexecutor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-interface ComponentDependency {
- ListenableFuture<Double> doubleDep();
-}
diff --git a/javatests/dagger/functional/producers/badexecutor/SimpleComponent.java b/javatests/dagger/functional/producers/badexecutor/SimpleComponent.java
deleted file mode 100644
index ea58125..0000000
--- a/javatests/dagger/functional/producers/badexecutor/SimpleComponent.java
+++ /dev/null
@@ -1,43 +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.functional.producers.badexecutor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProductionComponent;
-
-/**
- * A component that contains entry points that exercise different execution paths, for verifying the
- * behavior when the executor throws a {@link java.util.concurrent.RejectedExecutionException}.
- */
-@ProductionComponent(
- dependencies = ComponentDependency.class,
- modules = {ExecutorModule.class, SimpleProducerModule.class}
-)
-interface SimpleComponent {
- /** An entry point exposing a producer method with no args. */
- ListenableFuture<String> noArgStr();
-
- /** An entry point exposing a producer method that depends on another producer method. */
- ListenableFuture<Integer> singleArgInt();
-
- /** An entry point exposing a producer method that depends on a component dependency method. */
- ListenableFuture<Boolean> singleArgBool();
-
- /** An entry point exposing a component dependency method. */
- ListenableFuture<Double> doubleDep();
-}
diff --git a/javatests/dagger/functional/producers/badexecutor/SimpleProducerModule.java b/javatests/dagger/functional/producers/badexecutor/SimpleProducerModule.java
deleted file mode 100644
index f907fda..0000000
--- a/javatests/dagger/functional/producers/badexecutor/SimpleProducerModule.java
+++ /dev/null
@@ -1,38 +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.functional.producers.badexecutor;
-
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-@ProducerModule
-final class SimpleProducerModule {
- @Produces
- static String noArgStr() {
- return "no arg string";
- }
-
- @Produces
- static int singleArgInt(String arg) {
- return arg.length();
- }
-
- @Produces
- static boolean singleArgBool(double arg) {
- return arg > 0.0;
- }
-}
diff --git a/javatests/dagger/functional/producers/binds/BindsProducersTest.java b/javatests/dagger/functional/producers/binds/BindsProducersTest.java
deleted file mode 100644
index 0949f02..0000000
--- a/javatests/dagger/functional/producers/binds/BindsProducersTest.java
+++ /dev/null
@@ -1,79 +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.functional.producers.binds;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class BindsProducersTest {
-
- private SimpleBindsProductionComponent component;
-
- @Before
- public void setUp() {
- component = DaggerSimpleBindsProductionComponent.create();
- }
-
- @Test
- public void bindDelegates() throws Exception {
- assertThat(component.object().get()).isInstanceOf(FooOfStrings.class);
- assertThat(component.fooOfStrings().get()).isInstanceOf(FooOfStrings.class);
- assertThat(component.fooOfIntegers().get()).isNotNull();
- }
-
- @Test
- public void bindWithScope() throws Exception {
- assertThat(component.qualifiedFooOfStrings().get())
- .isSameInstanceAs(component.qualifiedFooOfStrings().get());
- }
-
- @Test
- public void multibindings() throws Exception {
- assertThat(component.foosOfNumbers().get()).hasSize(2);
- assertThat(component.objects().get()).hasSize(3);
- assertThat(component.charSequences().get()).hasSize(5);
-
- assertThat(component.integerObjectMap().get())
- .containsExactly(
- 123, "123-string", 456, "456-string", 789, "789-string", -1, "provision-string");
-
- Map<Integer, Producer<Object>> integerProducerOfObjectMap =
- component.integerProducerOfObjectMap().get();
- assertThat(integerProducerOfObjectMap).hasSize(4);
- assertThat(integerProducerOfObjectMap.get(123).get().get()).isEqualTo("123-string");
- assertThat(integerProducerOfObjectMap.get(456).get().get()).isEqualTo("456-string");
- assertThat(integerProducerOfObjectMap.get(789).get().get()).isEqualTo("789-string");
- assertThat(integerProducerOfObjectMap.get(-1).get().get()).isEqualTo("provision-string");
-
- assertThat(component.integerProducedOfObjectMap().get())
- .containsExactly(
- 123, Produced.successful("123-string"),
- 456, Produced.successful("456-string"),
- 789, Produced.successful("789-string"),
- -1, Produced.successful("provision-string"));
-
- assertThat(component.qualifiedIntegerObjectMap().get()).hasSize(1);
- }
-}
diff --git a/javatests/dagger/functional/producers/binds/Foo.java b/javatests/dagger/functional/producers/binds/Foo.java
deleted file mode 100644
index 4eb71fd..0000000
--- a/javatests/dagger/functional/producers/binds/Foo.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.
- */
-
-package dagger.functional.producers.binds;
-
-/**
- * This is the type that will be bound. We throw in generics just to complicate the test.
- */
-interface Foo<T> {}
diff --git a/javatests/dagger/functional/producers/binds/FooOfStrings.java b/javatests/dagger/functional/producers/binds/FooOfStrings.java
deleted file mode 100644
index b94d907..0000000
--- a/javatests/dagger/functional/producers/binds/FooOfStrings.java
+++ /dev/null
@@ -1,27 +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.functional.producers.binds;
-
-/**
- * This is not marked with {@link javax.inject.Inject @Inject} in order to test that {@link
- * dagger.Binds @Binds} properly translate to {@code dagger.internal.codegen.ProductionBinding}s
- * when the right-hand-side of the method is also a production binding. We force this by adding a
- * {@link dagger.producers.Produces @Produces} method to add it to the graph instead of relying on
- * the {@code dagger.internal.codegen.ProvisionBinding} that would be created by default with an
- * {@code @Inject} constructor.
- */
-final class FooOfStrings implements Foo<String> {}
diff --git a/javatests/dagger/functional/producers/binds/SimpleBindingModule.java b/javatests/dagger/functional/producers/binds/SimpleBindingModule.java
deleted file mode 100644
index f2af277..0000000
--- a/javatests/dagger/functional/producers/binds/SimpleBindingModule.java
+++ /dev/null
@@ -1,177 +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.functional.producers.binds;
-
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.Executor;
-import javax.inject.Named;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-
-@ProducerModule(includes = {
- SimpleBindingModule.ExecutorModule.class,
- SimpleBindingModule.ProvisionModuleForMap.class
-})
-abstract class SimpleBindingModule {
- @Binds
- abstract Object bindObject(FooOfStrings impl);
-
- @Binds
- abstract Foo<String> bindFooOfStrings(FooOfStrings impl);
-
- @Binds
- abstract Foo<? extends Number> bindFooOfNumbers(Foo<Integer> fooOfIntegers);
-
- @Binds
- @Singleton
- @SomeQualifier
- abstract Foo<String> bindQualifiedFooOfStrings(FooOfStrings impl);
-
- @Produces
- static FooOfStrings produceFooOfStrings() {
- return new FooOfStrings();
- }
-
- @Produces
- static Foo<Integer> produceFooOfIntegers() {
- return new Foo<Integer>() {};
- }
-
- @Produces
- static Foo<Double> produceFooOfDoubles() {
- return new Foo<Double>() {};
- }
-
- @Binds
- @IntoSet
- abstract Foo<? extends Number> bindFooOfIntegersIntoSet(Foo<Integer> fooOfIntegers);
-
- @Binds
- @IntoSet
- abstract Foo<? extends Number> bindFooExtendsNumberIntoSet(Foo<Double> fooOfDoubles);
-
- @Binds
- @ElementsIntoSet
- abstract Set<Object> bindSetOfFooNumbersToObjects(Set<Foo<? extends Number>> setOfFooNumbers);
-
- @Binds
- @IntoSet
- abstract Object bindFooOfStringsIntoSetOfObjects(FooOfStrings impl);
-
- @Produces
- static HashSet<String> produceStringHashSet() {
- return new HashSet<>(Arrays.asList("hash-string1", "hash-string2"));
- }
-
- @Produces
- static TreeSet<CharSequence> produceCharSequenceTreeSet() {
- return new TreeSet<CharSequence>(Arrays.asList("tree-charSequence1", "tree-charSequence2"));
- }
-
- @Produces
- static Collection<CharSequence> produceCharSequenceCollection() {
- return Arrays.<CharSequence>asList("list-charSequence");
- }
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindHashSetOfStrings(HashSet<String> set);
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindTreeSetOfCharSequences(TreeSet<CharSequence> set);
-
- @Binds
- @ElementsIntoSet
- abstract Set<CharSequence> bindCollectionOfCharSequences(Collection<CharSequence> collection);
-
- @Qualifier
- @Retention(RetentionPolicy.RUNTIME)
- @interface SomeQualifier {}
-
- @Module
- static final class ExecutorModule {
- @Provides @Production
- static Executor provideExecutor() {
- return MoreExecutors.directExecutor();
- }
- }
-
- @Binds
- @IntoMap
- @IntKey(123)
- abstract Object bind123ForMap(@Named("For-123") String string);
-
- @Binds
- @IntoMap
- @IntKey(456)
- abstract Object bind456ForMap(@Named("For-456") String string);
-
- @Produces
- @IntoMap
- @IntKey(789)
- static Object produce789ForMap() {
- return "789-string";
- }
-
- @Module
- abstract static class ProvisionModuleForMap {
- @Provides @Named("Provision string") static String provideProvisionString() {
- return "provision-string";
- }
-
- @Binds
- @IntoMap
- @IntKey(-1)
- abstract Object bindNegative1ForMap(@Named("Provision string") String string);
- }
-
- @Binds
- @IntoMap
- @IntKey(123)
- @SomeQualifier
- abstract Object bindFooOfStringsIntoQualifiedMap(FooOfStrings fooOfStrings);
-
- @Produces
- @Named("For-123")
- static String produce123String() {
- return "123-string";
- }
-
- @Produces
- @Named("For-456")
- static String produce456String() {
- return "456-string";
- }
-}
diff --git a/javatests/dagger/functional/producers/binds/SimpleBindsProductionComponent.java b/javatests/dagger/functional/producers/binds/SimpleBindsProductionComponent.java
deleted file mode 100644
index 21cf661..0000000
--- a/javatests/dagger/functional/producers/binds/SimpleBindsProductionComponent.java
+++ /dev/null
@@ -1,53 +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.functional.producers.binds;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.binds.SimpleBindingModule.SomeQualifier;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProductionComponent;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Singleton;
-
-@Singleton
-@ProductionComponent(modules = SimpleBindingModule.class)
-public interface SimpleBindsProductionComponent {
- ListenableFuture<Object> object();
-
- ListenableFuture<Foo<String>> fooOfStrings();
-
- @SomeQualifier
- ListenableFuture<Foo<String>> qualifiedFooOfStrings();
-
- ListenableFuture<Foo<Integer>> fooOfIntegers();
-
- ListenableFuture<Set<Foo<? extends Number>>> foosOfNumbers();
-
- ListenableFuture<Set<Object>> objects();
-
- ListenableFuture<Set<CharSequence>> charSequences();
-
- ListenableFuture<Map<Integer, Object>> integerObjectMap();
-
- ListenableFuture<Map<Integer, Producer<Object>>> integerProducerOfObjectMap();
-
- ListenableFuture<Map<Integer, Produced<Object>>> integerProducedOfObjectMap();
-
- @SomeQualifier ListenableFuture<Map<Integer, Object>> qualifiedIntegerObjectMap();
-}
diff --git a/javatests/dagger/functional/producers/builder/DepComponent.java b/javatests/dagger/functional/producers/builder/DepComponent.java
deleted file mode 100644
index c2811f1..0000000
--- a/javatests/dagger/functional/producers/builder/DepComponent.java
+++ /dev/null
@@ -1,23 +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.functional.producers.builder;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-interface DepComponent {
- ListenableFuture<Double> d();
-}
diff --git a/javatests/dagger/functional/producers/builder/IntModule.java b/javatests/dagger/functional/producers/builder/IntModule.java
deleted file mode 100644
index ed2bb95..0000000
--- a/javatests/dagger/functional/producers/builder/IntModule.java
+++ /dev/null
@@ -1,28 +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.functional.producers.builder;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class IntModule {
- @Provides
- static int i() {
- return 42;
- }
-}
diff --git a/javatests/dagger/functional/producers/builder/ProductionComponentBuilderTest.java b/javatests/dagger/functional/producers/builder/ProductionComponentBuilderTest.java
deleted file mode 100644
index 14f153e..0000000
--- a/javatests/dagger/functional/producers/builder/ProductionComponentBuilderTest.java
+++ /dev/null
@@ -1,67 +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.functional.producers.builder;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link dagger.producers.ProductionComponent.Builder}. */
-@RunWith(JUnit4.class)
-public final class ProductionComponentBuilderTest {
-
- @Test
- public void successfulBuild() throws Exception {
- TestComponentWithBuilder component =
- DaggerTestComponentWithBuilder.builder()
- .depComponent(depComponent(15.3))
- .strModule(new StringModule())
- .build();
- assertThat(component.s().get()).isEqualTo("arg: 42");
- assertThat(component.d().get()).isEqualTo(15.3);
- }
-
- @Test
- public void successfulBuild_withMissingZeroArgModule() throws Exception {
- TestComponentWithBuilder component =
- DaggerTestComponentWithBuilder.builder()
- .depComponent(depComponent(15.3))
- .build();
- assertThat(component.s().get()).isEqualTo("arg: 42");
- assertThat(component.d().get()).isEqualTo(15.3);
- }
-
- @Test(expected = IllegalStateException.class)
- public void missingDepComponent() {
- DaggerTestComponentWithBuilder.builder()
- .strModule(new StringModule())
- .build();
- }
-
- private static DepComponent depComponent(final double value) {
- return new DepComponent() {
- @Override
- public ListenableFuture<Double> d() {
- return Futures.immediateFuture(value);
- }
- };
- }
-}
diff --git a/javatests/dagger/functional/producers/builder/StringModule.java b/javatests/dagger/functional/producers/builder/StringModule.java
deleted file mode 100644
index 6ad748f..0000000
--- a/javatests/dagger/functional/producers/builder/StringModule.java
+++ /dev/null
@@ -1,28 +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.functional.producers.builder;
-
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-@ProducerModule
-final class StringModule {
- @Produces
- static String str(int i) {
- return "arg: " + i;
- }
-}
diff --git a/javatests/dagger/functional/producers/builder/TestComponentWithBuilder.java b/javatests/dagger/functional/producers/builder/TestComponentWithBuilder.java
deleted file mode 100644
index 91fb326..0000000
--- a/javatests/dagger/functional/producers/builder/TestComponentWithBuilder.java
+++ /dev/null
@@ -1,37 +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.functional.producers.builder;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProductionComponent;
-
-@ProductionComponent(
- modules = {ExecutorModule.class, StringModule.class, IntModule.class},
- dependencies = DepComponent.class
-)
-interface TestComponentWithBuilder {
- ListenableFuture<String> s();
- ListenableFuture<Double> d();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder depComponent(DepComponent depComponent);
- Builder strModule(StringModule strModule);
- TestComponentWithBuilder build();
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/CancellationComponent.java b/javatests/dagger/functional/producers/cancellation/CancellationComponent.java
deleted file mode 100644
index f06829e..0000000
--- a/javatests/dagger/functional/producers/cancellation/CancellationComponent.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.functional.producers.cancellation;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.BindsInstance;
-import dagger.functional.producers.cancellation.CancellationComponent.Dependency;
-import dagger.producers.Producer;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import java.util.concurrent.Executor;
-import javax.inject.Named;
-
-@ProductionComponent(modules = CancellationModule.class, dependencies = Dependency.class)
-interface CancellationComponent {
-
- @Named("ep1")
- ListenableFuture<String> entryPoint1();
-
- @Named("ep2")
- Producer<String> entryPoint2();
-
- @Named("ep3")
- ListenableFuture<String> entryPoint3();
-
- CancellationSubcomponent.Builder subcomponentBuilder();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder module(CancellationModule module);
-
- Builder dependency(Dependency dependency);
-
- @BindsInstance
- Builder executor(@Production Executor executor);
-
- CancellationComponent build();
- }
-
- final class Dependency {
-
- final ProducerTester tester;
-
- Dependency(ProducerTester tester) {
- this.tester = checkNotNull(tester);
- }
-
- @SuppressWarnings("unused") // Dagger uses it
- ListenableFuture<String> getDependencyFuture() {
- return tester.start("dependencyFuture");
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/CancellationModule.java b/javatests/dagger/functional/producers/cancellation/CancellationModule.java
deleted file mode 100644
index ff7ee79..0000000
--- a/javatests/dagger/functional/producers/cancellation/CancellationModule.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.functional.producers.cancellation;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.Provides;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import javax.inject.Named;
-
-@SuppressWarnings("unused") // not actually using dependencies
-@ProducerModule(subcomponents = CancellationSubcomponent.class)
-final class CancellationModule {
-
- private final ProducerTester tester;
-
- CancellationModule(ProducerTester tester) {
- this.tester = checkNotNull(tester);
- }
-
- @Produces
- @Named("leaf1")
- ListenableFuture<String> produceLeaf1() {
- return tester.start("leaf1");
- }
-
- @Produces
- @Named("leaf2")
- ListenableFuture<String> produceLeaf2() {
- return tester.start("leaf2");
- }
-
- @Produces
- @Named("leaf3")
- ListenableFuture<String> produceLeaf3() {
- return tester.start("leaf3");
- }
-
- @Produces
- @Named("foo")
- ListenableFuture<String> produceFoo(@Named("leaf1") String leaf1, @Named("leaf2") String leaf2) {
- return tester.start("foo");
- }
-
- @Produces
- @Named("bar")
- ListenableFuture<String> produceBar(@Named("leaf2") String leaf2, @Named("leaf3") String leaf3) {
- return tester.start("bar");
- }
-
- @Produces
- @Named("baz")
- ListenableFuture<String> produceBaz(
- @Named("foo") Producer<String> foo, @Named("bar") String bar) {
- ListenableFuture<String> fooFuture = foo.get();
- if (!fooFuture.isDone()) {
- assertThat(fooFuture.cancel(true)).isTrue();
- assertThat(fooFuture.isCancelled()).isTrue();
- }
- return tester.start("baz");
- }
-
- @Provides
- @Named("providesDep")
- static String provideProvidesDep() {
- return "providesDep";
- }
-
- @Produces
- @Named("qux")
- ListenableFuture<String> produceQux(
- @Named("baz") String baz, @Named("providesDep") String providesDep) {
- return tester.start("qux");
- }
-
- @Produces
- @Named("ep1")
- ListenableFuture<String> produceEntryPoint1(@Named("qux") String qux) {
- return tester.start("entryPoint1");
- }
-
- @Produces
- @Named("ep2")
- ListenableFuture<String> produceEntryPoint2(@Named("bar") String bar, String dependency) {
- return tester.start("entryPoint2");
- }
-
- @Produces
- @Named("ep3")
- static ListenableFuture<String> produceEntryPoint3(Producer<String> dependencyProducer) {
- ListenableFuture<String> dependencyFuture = dependencyProducer.get();
- assertThat(dependencyFuture.isDone()).isFalse();
- assertThat(dependencyFuture.cancel(true)).isTrue();
- assertThat(dependencyFuture.isCancelled()).isTrue();
- return dependencyFuture;
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/CancellationPolicyTest.java b/javatests/dagger/functional/producers/cancellation/CancellationPolicyTest.java
deleted file mode 100644
index 936072a..0000000
--- a/javatests/dagger/functional/producers/cancellation/CancellationPolicyTest.java
+++ /dev/null
@@ -1,180 +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.functional.producers.cancellation;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.BindsInstance;
-import dagger.producers.CancellationPolicy;
-import dagger.producers.CancellationPolicy.Propagation;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.util.concurrent.Executor;
-import javax.inject.Named;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for parent production components with a {@code CancellationPolicy} that allows subcomponent
- * cancellation to propagate to them
- */
-@RunWith(JUnit4.class)
-public final class CancellationPolicyTest {
-
- @ProducerModule(subcomponents = Child.class)
- static class ParentModule {
- private final ProducerTester tester;
-
- ParentModule(ProducerTester tester) {
- this.tester = tester;
- }
-
- @Produces
- @Named("a")
- ListenableFuture<String> produceA() {
- return tester.start("a");
- }
- }
-
- interface Parent {
- @Named("a")
- ListenableFuture<String> a();
-
- Child.Builder childBuilder();
-
- interface Builder<P extends Parent, B extends Builder<P, B>> {
- B module(ParentModule module);
-
- @BindsInstance
- B executor(@Production Executor executor);
-
- P build();
- }
- }
-
- @CancellationPolicy(fromSubcomponents = Propagation.PROPAGATE)
- @ProductionComponent(modules = ParentModule.class)
- interface PropagatingParent extends Parent {
- @ProductionComponent.Builder
- interface Builder extends Parent.Builder<PropagatingParent, Builder> {}
- }
-
- @CancellationPolicy(fromSubcomponents = Propagation.IGNORE)
- @ProductionComponent(modules = ParentModule.class)
- interface NonPropagatingParent extends Parent {
- @ProductionComponent.Builder
- interface Builder extends Parent.Builder<NonPropagatingParent, Builder> {}
- }
-
- @ProducerModule
- static class ChildModule {
- private final ProducerTester tester;
-
- ChildModule(ProducerTester tester) {
- this.tester = tester;
- }
-
- @Produces
- @Named("b")
- ListenableFuture<String> b(@Named("a") String a) {
- return tester.start("b");
- }
- }
-
- @ProductionSubcomponent(modules = ChildModule.class)
- interface Child {
- @Named("b")
- ListenableFuture<String> b();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- Builder module(ChildModule module);
-
- Child build();
- }
- }
-
- private final ProducerTester tester = new ProducerTester();
-
- @Test
- public void propagatingParent_childCancellationPropagatesToParent() {
- PropagatingParent parent =
- DaggerCancellationPolicyTest_PropagatingParent.builder()
- .module(new ParentModule(tester))
- .executor(MoreExecutors.directExecutor())
- .build();
- ListenableFuture<String> a = parent.a();
-
- Child child = parent.childBuilder().module(new ChildModule(tester)).build();
-
- ListenableFuture<String> b = child.b();
-
- tester.assertStarted("a").only();
-
- assertThat(a.isDone()).isFalse();
- assertThat(b.isDone()).isFalse();
-
- assertThat(b.cancel(true)).isTrue();
- assertThat(b.isCancelled()).isTrue();
-
- tester.assertCancelled("a");
-
- assertThat(a.isCancelled()).isTrue();
- }
-
- @Test
- public void nonPropagatingParent_childCancellationDoesNotPropagateToParent() throws Exception {
- // This test is basically just checking that when the parent has fromSubcomponents = IGNORE, it
- // behaves the same as having no @CancellationPolicy at all (as tested in
- // ProducerSubcomponentCancellationTester)
- NonPropagatingParent parent =
- DaggerCancellationPolicyTest_NonPropagatingParent.builder()
- .module(new ParentModule(tester))
- .executor(MoreExecutors.directExecutor())
- .build();
- ListenableFuture<String> a = parent.a();
-
- Child child = parent.childBuilder().module(new ChildModule(tester)).build();
-
- ListenableFuture<String> b = child.b();
-
- tester.assertStarted("a").only();
-
- assertThat(a.isDone()).isFalse();
- assertThat(b.isDone()).isFalse();
-
- assertThat(b.cancel(true)).isTrue();
- assertThat(b.isCancelled()).isTrue();
-
- tester.assertNotCancelled("a");
-
- assertThat(a.isDone()).isFalse();
-
- tester.complete("a");
- assertThat(a.isDone()).isTrue();
- assertThat(a.get(1, MILLISECONDS)).isEqualTo("completed");
-
- tester.assertNotStarted("b");
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/CancellationSubcomponent.java b/javatests/dagger/functional/producers/cancellation/CancellationSubcomponent.java
deleted file mode 100644
index 63b1a9d..0000000
--- a/javatests/dagger/functional/producers/cancellation/CancellationSubcomponent.java
+++ /dev/null
@@ -1,35 +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.functional.producers.cancellation;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProductionSubcomponent;
-import javax.inject.Named;
-
-@ProductionSubcomponent(modules = CancellationSubcomponentModule.class)
-interface CancellationSubcomponent {
-
- @Named("subEntryPoint")
- ListenableFuture<String> subcomponentEntryPoint();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- Builder module(CancellationSubcomponentModule module);
-
- CancellationSubcomponent build();
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/CancellationSubcomponentModule.java b/javatests/dagger/functional/producers/cancellation/CancellationSubcomponentModule.java
deleted file mode 100644
index 9cedad4..0000000
--- a/javatests/dagger/functional/producers/cancellation/CancellationSubcomponentModule.java
+++ /dev/null
@@ -1,66 +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.functional.producers.cancellation;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import javax.inject.Named;
-
-@SuppressWarnings("unused") // not actually using dependencies
-@ProducerModule
-final class CancellationSubcomponentModule {
-
- private final ProducerTester tester;
-
- CancellationSubcomponentModule(ProducerTester tester) {
- this.tester = checkNotNull(tester);
- }
-
- @Produces
- @Named("subLeaf")
- ListenableFuture<String> produceSubLeaf() {
- return tester.start("subLeaf");
- }
-
- @Produces
- @Named("subTask1")
- ListenableFuture<String> produceSubTask1(
- @Named("subLeaf") String subLeaf, @Named("qux") String qux) {
- return tester.start("subTask1");
- }
-
- @Produces
- @Named("subTask2")
- ListenableFuture<String> produceSubTask2(@Named("foo") String foo, Producer<String> dependency) {
- ListenableFuture<String> dependencyFuture = dependency.get();
- assertThat(dependencyFuture.cancel(true)).isTrue();
- assertThat(dependencyFuture.isCancelled()).isTrue();
- return tester.start("subTask2");
- }
-
- @Produces
- @Named("subEntryPoint")
- ListenableFuture<String> produceSubEntryPoint(
- @Named("subTask1") String subTask1, @Named("subTask2") String subTask2) {
- return tester.start("subEntryPoint");
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/ProducerCancellationTest.java b/javatests/dagger/functional/producers/cancellation/ProducerCancellationTest.java
deleted file mode 100644
index 23b31d2..0000000
--- a/javatests/dagger/functional/producers/cancellation/ProducerCancellationTest.java
+++ /dev/null
@@ -1,117 +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.functional.producers.cancellation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.functional.producers.cancellation.CancellationComponent.Dependency;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests cancellation of tasks in production components. */
-@RunWith(JUnit4.class)
-public class ProducerCancellationTest {
-
- private final ProducerTester tester = new ProducerTester();
- private final CancellationComponent component =
- DaggerCancellationComponent.builder()
- .module(new CancellationModule(tester))
- .dependency(new Dependency(tester))
- .executor(MoreExecutors.directExecutor())
- .build();
-
- @Test
- public void initialState() {
- tester.assertNoStartedNodes();
- }
-
- @Test
- public void cancellingOneEntryPoint_cancelsAllRunningNodes() {
- ListenableFuture<String> entryPoint1 = component.entryPoint1();
- tester.assertStarted("leaf2", "leaf3").only();
-
- assertThat(entryPoint1.cancel(true)).isTrue();
- assertThat(entryPoint1.isCancelled()).isTrue();
-
- tester.assertCancelled("leaf2", "leaf3").only();
-
- // The other entry points were also cancelled in the process, from the user's perspective.
- assertThat(component.entryPoint2().get().isCancelled()).isTrue();
- assertThat(component.entryPoint3().isCancelled()).isTrue();
-
- // The underlying tasks weren't actually started, even though we just requested them above,
- // because the node was cancelled already along with the component.
- tester.assertNotStarted("entryPoint2", "entryPoint3");
- }
-
- @SuppressWarnings({"CheckReturnValue", "FutureReturnValueIgnored"})
- @Test
- public void cancellingNonEntryPointProducer_doesNotCancelUnderlyingTask() {
- ListenableFuture<String> entryPoint1 = component.entryPoint1();
- tester.assertStarted("leaf2", "leaf3").only();
-
- tester.complete("leaf2", "leaf3");
-
- tester.assertStarted("bar");
-
- // foo's dependencies are complete, but it is not yet started because baz depends on
- // Producer<foo>, so it won't be started until baz calls get() on it.
- // baz not started yet because it needs bar to complete first.
- tester.assertNotStarted("foo", "baz");
-
- // Complete bar, triggering baz to run. It calls get() on the foo Producer, so that also starts
- // once its dependency leaf1 is complete.
- tester.complete("bar", "leaf1");
- tester.assertStarted("baz", "foo");
-
- // baz then cancelled the foo Producer's future, but that didn't cancel the underlying task.
- tester.assertNotCancelled("foo");
-
- // If we cancel the entry point, that does cancel the task.
- entryPoint1.cancel(true);
- tester.assertCancelled("foo");
- }
-
- @SuppressWarnings({"CheckReturnValue", "FutureReturnValueIgnored"})
- @Test
- public void cancellingProducerFromComponentDependency_cancelsUnderlyingTask() {
- // Start leaf2/leaf3 tasks.
- component.entryPoint1();
- tester.assertStarted("leaf2", "leaf3").only();
- tester.assertNotCancelled("leaf2", "leaf3");
-
- // Nothing's requested dependencyFuture yet.
- tester.assertNotStarted("dependencyFuture");
-
- // entryPoint3 injects Producer of dependency future, then cancels that future. Then also
- // returns that future as the entry point.
- ListenableFuture<String> entryPoint = component.entryPoint3();
-
- tester.assertStarted("dependencyFuture");
- tester.assertCancelled("dependencyFuture");
-
- // Even though the entry point future returned from the component is not the dependency future
- // itself, the cancellation should have propagated out to it and cancelled it.
- assertThat(entryPoint.isCancelled()).isTrue();
-
- // And that cancellation should have cancelled the other tasks running in the component.
- tester.assertCancelled("leaf2", "leaf3");
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/ProducerSubcomponentCancellationTest.java b/javatests/dagger/functional/producers/cancellation/ProducerSubcomponentCancellationTest.java
deleted file mode 100644
index 246bf9f..0000000
--- a/javatests/dagger/functional/producers/cancellation/ProducerSubcomponentCancellationTest.java
+++ /dev/null
@@ -1,122 +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.functional.producers.cancellation;
-
-import static com.google.common.truth.Truth.assertThat;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import dagger.functional.producers.cancellation.CancellationComponent.Dependency;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests cancellation of tasks in production subcomponents. */
-@RunWith(JUnit4.class)
-public class ProducerSubcomponentCancellationTest {
-
- private final ProducerTester tester = new ProducerTester();
- private final CancellationComponent component =
- DaggerCancellationComponent.builder()
- .module(new CancellationModule(tester))
- .dependency(new Dependency(tester))
- .executor(MoreExecutors.directExecutor())
- .build();
- private final CancellationSubcomponent subcomponent =
- component.subcomponentBuilder().module(new CancellationSubcomponentModule(tester)).build();
-
- @Test
- public void initialState() {
- tester.assertNoStartedNodes();
- }
-
- @Test
- public void cancellingSubcomponent_doesNotCancelParent() throws Exception {
- ListenableFuture<String> subcomponentEntryPoint = subcomponent.subcomponentEntryPoint();
-
- // Subcomponent entry point depends on all leaves from the parent component and on the single
- // leaf in the subcomponent itself, so they should all have started.
- tester.assertStarted("leaf1", "leaf2", "leaf3", "subLeaf").only();
-
- assertThat(subcomponentEntryPoint.cancel(true)).isTrue();
- assertThat(subcomponentEntryPoint.isCancelled()).isTrue();
-
- // None of the tasks running in the parent were cancelled.
- tester.assertNotCancelled("leaf1", "leaf2", "leaf3");
- tester.assertCancelled("subLeaf").only();
-
- // Finish all the parent tasks to ensure that it can still complete normally.
- tester.complete(
- "dependencyFuture",
- "leaf1",
- "leaf2",
- "leaf3",
- "foo",
- "bar",
- "baz",
- "qux",
- "entryPoint1",
- "entryPoint2");
-
- assertThat(component.entryPoint1().get(1, MILLISECONDS)).isEqualTo("completed");
- assertThat(component.entryPoint2().get().get(1, MILLISECONDS)).isEqualTo("completed");
- }
-
- @Test
- public void cancellingSubcomponent_preventsUnstartedNodesFromStarting() {
- ListenableFuture<String> subcomponentEntryPoint = subcomponent.subcomponentEntryPoint();
-
- tester.complete("subLeaf");
- tester.assertNotStarted("subTask1", "subTask2");
-
- subcomponentEntryPoint.cancel(true);
-
- // Complete the remaining dependencies of subTask1 and subTask2.
- tester.complete("leaf1", "leaf2", "leaf3", "foo", "bar", "baz", "qux");
-
- // Since the subcomponent was cancelled, they are not started.
- tester.assertNotStarted("subTask1", "subTask2");
- }
-
- @Test
- public void cancellingProducerFromComponentDependency_inSubcomponent_cancelsUnderlyingTask()
- throws Exception {
- // Request subcomponent's entry point.
- ListenableFuture<String> subcomponentEntryPoint = subcomponent.subcomponentEntryPoint();
-
- // Finish all parent tasks so that the subcomponent's tasks can start.
- tester.complete("leaf1", "leaf2", "leaf3", "foo", "bar", "baz", "qux", "subLeaf");
-
- tester.assertStarted("subTask1", "subTask2");
- tester.assertNotCancelled("subTask1", "subTask2");
-
- // When subTask2 runs, it cancels the dependency future.
- // TODO(cgdecker): Is this what we want to happen?
- // On the one hand, there's a policy of "futures from component dependencies come from outside
- // our control and should be cancelled unconditionally". On the other hand, the dependency is
- // coming from the parent component, and the policy is also not to cancel things belonging to
- // the parent unless it allows that.
- tester.assertCancelled("dependencyFuture");
-
- // The future it returns didn't depend directly on that future, though, so the subcomponent
- // should be able to complete normally.
- tester.complete("subTask1", "subTask2", "subEntryPoint");
-
- assertThat(subcomponentEntryPoint.get(1, MILLISECONDS)).isEqualTo("completed");
- }
-}
diff --git a/javatests/dagger/functional/producers/cancellation/ProducerTester.java b/javatests/dagger/functional/producers/cancellation/ProducerTester.java
deleted file mode 100644
index 35cf8e9..0000000
--- a/javatests/dagger/functional/producers/cancellation/ProducerTester.java
+++ /dev/null
@@ -1,212 +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.functional.producers.cancellation;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.AbstractFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Predicate;
-
-/**
- * Helper for testing producers.
- *
- * <p>Maintains a set of nodes (futures mapped to names) representing the results of different
- * producer nodes and allows those nodes to be "started" (when returned from a producer method),
- * completed, and cancelled, as well as to be queried for their state. Additionally, provides
- * assertions about the state of nodes.
- */
-final class ProducerTester {
-
- private final Map<String, TestFuture> futures = new HashMap<>();
-
- /** Starts the given node. */
- ListenableFuture<String> start(String node) {
- return getOrCreate(node).start();
- }
-
- private TestFuture getOrCreate(String node) {
- TestFuture result = futures.get(node);
- if (result == null) {
- result = new TestFuture(node);
- futures.put(node, result);
- }
- return result;
- }
-
- /** Returns whether or not the given node has been started. */
- boolean isStarted(String node) {
- return futures.containsKey(node) && futures.get(node).isStarted();
- }
-
- /** Completes of the given nodes. */
- void complete(String... nodes) {
- for (String node : nodes) {
- getOrCreate(node).complete();
- }
- }
-
- /** Returns whether or not the given node has been cancelled. */
- boolean isCancelled(String node) {
- TestFuture future = futures.get(node);
- return future != null && future.isCancelled();
- }
-
- /** Asserts that the given nodes have been started. */
- Only assertStarted(String... nodes) {
- return assertAboutNodes(STARTED, nodes);
- }
-
- /** Asserts that the given nodes have been cancelled. */
- Only assertCancelled(String... nodes) {
- return assertAboutNodes(CANCELLED, nodes);
- }
-
- /** Asserts that the given nodes have not been started. */
- Only assertNotStarted(String... nodes) {
- return assertAboutNodes(not(STARTED), nodes);
- }
-
- /** Asserts that the given nodes have not been cancelled. */
- Only assertNotCancelled(String... nodes) {
- return assertAboutNodes(not(CANCELLED), nodes);
- }
-
- /** Asserts that no nodes in this tester have been started. */
- void assertNoStartedNodes() {
- for (TestFuture future : futures.values()) {
- assertWithMessage("%s is started", future).that(future.isStarted()).isFalse();
- }
- }
-
- private Only assertAboutNodes(Predicate<? super TestFuture> assertion, String... nodes) {
- ImmutableSet.Builder<TestFuture> builder = ImmutableSet.builder();
- for (String node : nodes) {
- TestFuture future = getOrCreate(node);
- assertWithMessage("%s is %s", future, assertion).that(assertion.test(future)).isTrue();
- builder.add(future);
- }
- return new Only(builder.build(), assertion);
- }
-
- /**
- * Fluent class for making a previous assertion more strict by specifying that whatever was
- * asserted should be true only for the specified nodes and not for any others.
- */
- final class Only {
-
- private final ImmutableSet<TestFuture> expected;
- private final Predicate<? super TestFuture> assertion;
-
- Only(ImmutableSet<TestFuture> expected, Predicate<? super TestFuture> assertion) {
- this.expected = checkNotNull(expected);
- this.assertion = checkNotNull(assertion);
- }
-
- /**
- * Asserts that the previous assertion was not true for any node other than those that were
- * specified.
- */
- void only() {
- for (TestFuture future : futures.values()) {
- if (!expected.contains(future)) {
- assertWithMessage("%s is %s", future, assertion).that(assertion.test(future)).isFalse();
- }
- }
- }
- }
-
- /**
- * A simple future for testing that can be marked as having been started and which can be
- * completed with a result.
- */
- private static final class TestFuture extends AbstractFuture<String> {
-
- private final String name;
- private volatile boolean started;
-
- private TestFuture(String name) {
- this.name = checkNotNull(name);
- }
-
- /** Marks this future as having been started and returns it. */
- TestFuture start() {
- this.started = true;
- return this;
- }
-
- /** Returns whether or not this future's task was started. */
- boolean isStarted() {
- return started;
- }
-
- /** Completes this future's task by setting a value for it. */
- public void complete() {
- super.set("completed");
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- private static final Predicate<TestFuture> STARTED =
- new Predicate<TestFuture>() {
- @Override
- public boolean test(TestFuture future) {
- return future.isStarted();
- }
-
- @Override
- public String toString() {
- return "started";
- }
- };
-
- private static final Predicate<TestFuture> CANCELLED =
- new Predicate<TestFuture>() {
- @Override
- public boolean test(TestFuture future) {
- return future.isCancelled();
- }
-
- @Override
- public String toString() {
- return "cancelled";
- }
- };
-
- /** Version of Predicates.not with a toString() that's nicer for our assertion error messages. */
- private static <T> Predicate<T> not(final Predicate<T> predicate) {
- return new Predicate<T>() {
- @Override
- public boolean test(T input) {
- return !predicate.test(input);
- }
-
- @Override
- public String toString() {
- return "not " + predicate;
- }
- };
- }
-}
diff --git a/javatests/dagger/functional/producers/fluentfuture/FluentFutures.java b/javatests/dagger/functional/producers/fluentfuture/FluentFutures.java
deleted file mode 100644
index 7bb25f6..0000000
--- a/javatests/dagger/functional/producers/fluentfuture/FluentFutures.java
+++ /dev/null
@@ -1,88 +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.functional.producers.fluentfuture;
-
-import static com.google.common.util.concurrent.Futures.immediateFuture;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.FluentFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.BindsInstance;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-final class FluentFutures {
- interface Dependency {
- FluentFuture<Float> floatFuture();
- }
-
- @ProducerModule
- static final class Module {
- @Produces
- static FluentFuture<Integer> intFuture() {
- return FluentFuture.from(immediateFuture(5));
- }
-
- @Produces
- static FluentFuture<String> stringFuture(int i) {
- return FluentFuture.from(immediateFuture("hello"));
- }
-
- @Produces
- @IntoSet
- static FluentFuture<Double> doubleFuture(int i) {
- return FluentFuture.from(immediateFuture((double) i));
- }
-
- @Produces
- @IntoSet
- static double dependencyInput(float f) {
- return (double) f;
- }
-
- @Produces
- @ElementsIntoSet
- static Set<FluentFuture<Double>> setOfDoubleFutures(int i) {
- return ImmutableSet.of(
- FluentFuture.from(immediateFuture((double) i + 1)),
- FluentFuture.from(immediateFuture((double) i + 2)));
- }
- }
-
- @ProductionComponent(modules = Module.class, dependencies = Dependency.class)
- interface Component {
- ListenableFuture<String> string();
-
- ListenableFuture<Set<Double>> setOfDouble();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder dependency(Dependency dependency);
-
- @BindsInstance
- Builder executor(@Production Executor executor);
-
- Component build();
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/fluentfuture/FluentFuturesTest.java b/javatests/dagger/functional/producers/fluentfuture/FluentFuturesTest.java
deleted file mode 100644
index 8745860..0000000
--- a/javatests/dagger/functional/producers/fluentfuture/FluentFuturesTest.java
+++ /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.
- */
-
-package dagger.functional.producers.fluentfuture;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.util.concurrent.Futures.immediateFuture;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import com.google.common.util.concurrent.FluentFuture;
-import dagger.functional.producers.fluentfuture.FluentFutures.Component;
-import dagger.functional.producers.fluentfuture.FluentFutures.Dependency;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class FluentFuturesTest {
-
- @Test
- public void testFluentFutures() throws Exception {
- Component component =
- DaggerFluentFutures_Component.builder()
- .executor(directExecutor())
- .dependency(
- new Dependency() {
- @Override
- public FluentFuture<Float> floatFuture() {
- return FluentFuture.from(immediateFuture(42.0f));
- }
- })
- .build();
- assertThat(component.string().isDone()).isTrue();
- assertThat(component.string().get()).isEqualTo("hello");
- assertThat(component.setOfDouble().isDone()).isTrue();
- assertThat(component.setOfDouble().get()).containsExactly(5.0, 6.0, 7.0, 42.0);
- }
-}
diff --git a/javatests/dagger/functional/producers/gwt/GwtIncompatibles.java b/javatests/dagger/functional/producers/gwt/GwtIncompatibles.java
deleted file mode 100644
index 75efd96..0000000
--- a/javatests/dagger/functional/producers/gwt/GwtIncompatibles.java
+++ /dev/null
@@ -1,46 +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.functional.producers.gwt;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.lang.annotation.Retention;
-
-interface GwtIncompatibles {
- @Retention(RUNTIME)
- @interface GwtIncompatible {}
-
- @GwtIncompatible
- @ProducerModule
- class OnModule {
- @Produces
- static String onModule() {
- return "on module";
- }
- }
-
- @ProducerModule
- class OnMethod {
- @GwtIncompatible
- @Produces
- static String onMethod() {
- return "on method";
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/gwt/GwtIncompatiblesTest.java b/javatests/dagger/functional/producers/gwt/GwtIncompatiblesTest.java
deleted file mode 100644
index d484c8c..0000000
--- a/javatests/dagger/functional/producers/gwt/GwtIncompatiblesTest.java
+++ /dev/null
@@ -1,39 +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.functional.producers.gwt;
-
-import dagger.functional.producers.gwt.GwtIncompatibles.GwtIncompatible;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@code @GwtIncompatible} bindings. */
-@RunWith(JUnit4.class)
-public class GwtIncompatiblesTest {
- @Test
- public void testIncompatible() {
- assertGwtIncompatible(GwtIncompatibles_OnModule_OnModuleFactory.class);
- assertGwtIncompatible(GwtIncompatibles_OnMethod_OnMethodFactory.class);
- }
-
- private void assertGwtIncompatible(Class<?> clazz) {
- boolean gwtIncompatible = clazz.isAnnotationPresent(GwtIncompatible.class);
- if (!gwtIncompatible) {
- throw new AssertionError(clazz.getCanonicalName() + " is not @GwtIncompatible");
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/MonitoredComponent.java b/javatests/dagger/functional/producers/monitoring/MonitoredComponent.java
deleted file mode 100644
index 2df5645..0000000
--- a/javatests/dagger/functional/producers/monitoring/MonitoredComponent.java
+++ /dev/null
@@ -1,28 +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.functional.producers.monitoring;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProductionComponent;
-
-@ProductionComponent(
- modules = {ExecutorModule.class, MonitoringModule.class, StubModule.class, ServingModule.class}
-)
-interface MonitoredComponent {
- ListenableFuture<String> output();
-}
diff --git a/javatests/dagger/functional/producers/monitoring/MonitoringModule.java b/javatests/dagger/functional/producers/monitoring/MonitoringModule.java
deleted file mode 100644
index 3c08255..0000000
--- a/javatests/dagger/functional/producers/monitoring/MonitoringModule.java
+++ /dev/null
@@ -1,37 +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.functional.producers.monitoring;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-
-@Module
-final class MonitoringModule {
- private final ProductionComponentMonitor.Factory monitorFactory;
-
- MonitoringModule(ProductionComponentMonitor.Factory monitorFactory) {
- this.monitorFactory = monitorFactory;
- }
-
- @Provides
- @IntoSet
- ProductionComponentMonitor.Factory monitorFactory() {
- return monitorFactory;
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java b/javatests/dagger/functional/producers/monitoring/MonitoringTest.java
deleted file mode 100644
index 543835f..0000000
--- a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java
+++ /dev/null
@@ -1,254 +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.functional.producers.monitoring;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for production components using monitoring. */
-@RunWith(JUnit4.class)
-public final class MonitoringTest {
- @Mock private ProductionComponentMonitor.Factory componentMonitorFactory;
- @Mock private StringStub server1;
- @Mock private StringStub server2;
- private SettableFuture<String> server1Future;
- private SettableFuture<String> server2Future;
- private FakeProductionComponentMonitor componentMonitor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- componentMonitor = new FakeProductionComponentMonitor();
- when(componentMonitorFactory.create(any())).thenReturn(componentMonitor);
- server1Future = SettableFuture.create();
- server2Future = SettableFuture.create();
- when(server1.run(any(String.class))).thenReturn(server1Future);
- when(server2.run(any(String.class))).thenReturn(server2Future);
- }
-
- @Test
- public void basicMonitoring() throws Exception {
- MonitoredComponent component =
- DaggerMonitoredComponent.builder()
- .monitoringModule(new MonitoringModule(componentMonitorFactory))
- .stubModule(new StubModule(server1, server2))
- .build();
- ListenableFuture<String> output = component.output();
- assertThat(componentMonitor.monitors).hasSize(3);
- ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries =
- ImmutableList.copyOf(componentMonitor.monitors.entrySet());
- assertThat(entries.get(0).getKey().toString()).contains("CallServer2");
- assertThat(entries.get(1).getKey().toString()).contains("CallServer1");
- assertThat(entries.get(2).getKey().toString()).contains("RequestData");
-
- ProducerMonitor callServer2Monitor = entries.get(0).getValue();
- ProducerMonitor callServer1Monitor = entries.get(1).getValue();
- ProducerMonitor requestDataMonitor = entries.get(2).getValue();
-
- InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor);
- inOrder.verify(callServer2Monitor).requested();
- inOrder.verify(callServer1Monitor).requested();
- inOrder.verify(requestDataMonitor).requested();
- inOrder.verify(requestDataMonitor).ready();
- inOrder.verify(requestDataMonitor).methodStarting();
- inOrder.verify(requestDataMonitor).methodFinished();
- inOrder.verify(requestDataMonitor).succeeded("Hello, World!");
- inOrder.verify(callServer1Monitor).ready();
- inOrder.verify(callServer1Monitor).methodStarting();
- inOrder.verify(callServer1Monitor).methodFinished();
- verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
-
- server1Future.set("server 1 response");
- inOrder.verify(callServer1Monitor).succeeded("server 1 response");
- inOrder.verify(callServer2Monitor).ready();
- inOrder.verify(callServer2Monitor).methodStarting();
- inOrder.verify(callServer2Monitor).methodFinished();
- verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
-
- server2Future.set("server 2 response");
- inOrder.verify(callServer2Monitor).succeeded("server 2 response");
- verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
- assertThat(output.get()).isEqualTo("server 2 response");
- }
-
- @Test
- public void basicMonitoringWithFailure() throws Exception {
- MonitoredComponent component =
- DaggerMonitoredComponent.builder()
- .monitoringModule(new MonitoringModule(componentMonitorFactory))
- .stubModule(new StubModule(server1, server2))
- .build();
- ListenableFuture<String> output = component.output();
- assertThat(componentMonitor.monitors).hasSize(3);
- ImmutableList<Map.Entry<ProducerToken, ProducerMonitor>> entries =
- ImmutableList.copyOf(componentMonitor.monitors.entrySet());
- assertThat(entries.get(0).getKey().toString()).contains("CallServer2");
- assertThat(entries.get(1).getKey().toString()).contains("CallServer1");
- assertThat(entries.get(2).getKey().toString()).contains("RequestData");
-
- ProducerMonitor callServer2Monitor = entries.get(0).getValue();
- ProducerMonitor callServer1Monitor = entries.get(1).getValue();
- ProducerMonitor requestDataMonitor = entries.get(2).getValue();
-
- InOrder inOrder = inOrder(requestDataMonitor, callServer1Monitor, callServer2Monitor);
- inOrder.verify(callServer2Monitor).requested();
- inOrder.verify(callServer1Monitor).requested();
- inOrder.verify(requestDataMonitor).requested();
- inOrder.verify(requestDataMonitor).ready();
- inOrder.verify(requestDataMonitor).methodStarting();
- inOrder.verify(requestDataMonitor).methodFinished();
- inOrder.verify(requestDataMonitor).succeeded("Hello, World!");
- inOrder.verify(callServer1Monitor).ready();
- inOrder.verify(callServer1Monitor).methodStarting();
- inOrder.verify(callServer1Monitor).methodFinished();
- verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
-
- RuntimeException cause = new RuntimeException("monkey");
- server1Future.setException(cause);
- inOrder.verify(callServer1Monitor).failed(cause);
- inOrder.verify(callServer2Monitor).ready();
- inOrder.verify(callServer2Monitor).failed(any(Throwable.class));
- verifyNoMoreInteractions(requestDataMonitor, callServer1Monitor, callServer2Monitor);
- try {
- output.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(Throwables.getRootCause(e)).isSameInstanceAs(cause);
- }
- }
-
- private static final class FakeProductionComponentMonitor extends ProductionComponentMonitor {
- final Map<ProducerToken, ProducerMonitor> monitors = new LinkedHashMap<>();
-
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- ProducerMonitor monitor = mock(ProducerMonitor.class);
- monitors.put(token, monitor);
- return monitor;
- }
- }
-
- @Test
- public void monitoringWithThreads() throws Exception {
- ThreadRecordingProductionComponentMonitor componentMonitor =
- new ThreadRecordingProductionComponentMonitor();
- when(componentMonitorFactory.create(any())).thenReturn(componentMonitor);
-
- ThreadMonitoredComponent component =
- DaggerThreadMonitoredComponent.builder()
- .monitoringModule(new MonitoringModule(componentMonitorFactory))
- .executorModule(new ExecutorModule(Executors.newFixedThreadPool(10)))
- .build();
- ThreadAccumulator threadAccumulator = component.threadAccumulator().get();
-
- assertThat(componentMonitor.monitors).hasSize(3);
- ImmutableList<Map.Entry<ProducerToken, ThreadRecordingProducerMonitor>> entries =
- ImmutableList.copyOf(componentMonitor.monitors.entrySet());
-
- assertThat(entries.get(0).getKey().toString()).contains("EntryPoint");
- ThreadRecordingProducerMonitor entryPointMonitor = entries.get(0).getValue();
- assertThat(entries.get(1).getKey().toString()).contains("Required");
- ThreadRecordingProducerMonitor requiredMonitor = entries.get(1).getValue();
- assertThat(entries.get(2).getKey().toString()).contains("Deferred");
- ThreadRecordingProducerMonitor deferredMonitor = entries.get(2).getValue();
-
- // The entry point producer was requested from the main thread, then ran in its own thread.
- assertThat(entryPointMonitor.requestedThreadId).isEqualTo(Thread.currentThread().getId());
- assertThat(entryPointMonitor.startingThreadId)
- .isEqualTo(threadAccumulator.threadId("entryPoint"));
- assertThat(entryPointMonitor.finishedThreadId)
- .isEqualTo(threadAccumulator.threadId("entryPoint"));
-
- // The deferred producer was requested by the required producer, then ran in its own thread.
- assertThat(deferredMonitor.requestedThreadId).isEqualTo(threadAccumulator.threadId("required"));
- assertThat(deferredMonitor.startingThreadId).isEqualTo(threadAccumulator.threadId("deferred"));
- assertThat(deferredMonitor.finishedThreadId).isEqualTo(threadAccumulator.threadId("deferred"));
-
- // The required producer was requested by the entry point producer, then ran in its own thread.
- assertThat(requiredMonitor.requestedThreadId).isEqualTo(entryPointMonitor.requestedThreadId);
- assertThat(requiredMonitor.startingThreadId).isEqualTo(threadAccumulator.threadId("required"));
- assertThat(requiredMonitor.finishedThreadId).isEqualTo(threadAccumulator.threadId("required"));
-
- // Each producer ran in a distinct thread.
- ImmutableSet<Long> threadIds =
- ImmutableSet.of(
- Thread.currentThread().getId(),
- threadAccumulator.threadId("required"),
- threadAccumulator.threadId("deferred"),
- threadAccumulator.threadId("entryPoint"));
- assertThat(threadIds).hasSize(4);
- }
-
- private static final class ThreadRecordingProductionComponentMonitor
- extends ProductionComponentMonitor {
- final Map<ProducerToken, ThreadRecordingProducerMonitor> monitors = new LinkedHashMap<>();
-
- @Override
- public ProducerMonitor producerMonitorFor(ProducerToken token) {
- ThreadRecordingProducerMonitor monitor = new ThreadRecordingProducerMonitor();
- monitors.put(token, monitor);
- return monitor;
- }
- }
-
- private static final class ThreadRecordingProducerMonitor extends ProducerMonitor {
- private long requestedThreadId;
- private long startingThreadId;
- private long finishedThreadId;
-
- @Override
- public void requested() {
- requestedThreadId = Thread.currentThread().getId();
- }
-
- @Override
- public void methodStarting() {
- startingThreadId = Thread.currentThread().getId();
- }
-
- @Override
- public void methodFinished() {
- finishedThreadId = Thread.currentThread().getId();
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/ServingModule.java b/javatests/dagger/functional/producers/monitoring/ServingModule.java
deleted file mode 100644
index 09c9cd1..0000000
--- a/javatests/dagger/functional/producers/monitoring/ServingModule.java
+++ /dev/null
@@ -1,52 +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.functional.producers.monitoring;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.monitoring.StubModule.ForServer1;
-import dagger.functional.producers.monitoring.StubModule.ForServer2;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import javax.inject.Qualifier;
-
-@ProducerModule
-final class ServingModule {
- @Qualifier
- @interface RequestData {}
-
- @Qualifier
- @interface IntermediateData {}
-
- @Produces
- @RequestData
- static String requestData() {
- return "Hello, World!";
- }
-
- @Produces
- @IntermediateData
- static ListenableFuture<String> callServer1(
- @RequestData String data, @ForServer1 StringStub stub) {
- return stub.run(data);
- }
-
- @Produces
- static ListenableFuture<String> callServer2(
- @IntermediateData String data, @ForServer2 StringStub stub) {
- return stub.run(data);
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/StringStub.java b/javatests/dagger/functional/producers/monitoring/StringStub.java
deleted file mode 100644
index 2553e88..0000000
--- a/javatests/dagger/functional/producers/monitoring/StringStub.java
+++ /dev/null
@@ -1,23 +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.functional.producers.monitoring;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-interface StringStub {
- ListenableFuture<String> run(String input);
-}
diff --git a/javatests/dagger/functional/producers/monitoring/StubModule.java b/javatests/dagger/functional/producers/monitoring/StubModule.java
deleted file mode 100644
index 3c5893c..0000000
--- a/javatests/dagger/functional/producers/monitoring/StubModule.java
+++ /dev/null
@@ -1,50 +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.functional.producers.monitoring;
-
-import dagger.Module;
-import dagger.Provides;
-import javax.inject.Qualifier;
-
-@Module
-final class StubModule {
- @Qualifier
- @interface ForServer1 {}
-
- @Qualifier
- @interface ForServer2 {}
-
- private final StringStub server1;
- private final StringStub server2;
-
- StubModule(StringStub server1, StringStub server2) {
- this.server1 = server1;
- this.server2 = server2;
- }
-
- @Provides
- @ForServer1
- StringStub server1() {
- return server1;
- }
-
- @Provides
- @ForServer2
- StringStub server2() {
- return server2;
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/ThreadAccumulator.java b/javatests/dagger/functional/producers/monitoring/ThreadAccumulator.java
deleted file mode 100644
index 3d95fb6..0000000
--- a/javatests/dagger/functional/producers/monitoring/ThreadAccumulator.java
+++ /dev/null
@@ -1,38 +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.functional.producers.monitoring;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton
-final class ThreadAccumulator {
- private final Map<String, Long> threadIds = new ConcurrentHashMap<>();
-
- @Inject
- ThreadAccumulator() {}
-
- void markThread(String name) {
- threadIds.put(name, Thread.currentThread().getId());
- }
-
- long threadId(String name) {
- return threadIds.get(name);
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/ThreadModule.java b/javatests/dagger/functional/producers/monitoring/ThreadModule.java
deleted file mode 100644
index f55c3e0..0000000
--- a/javatests/dagger/functional/producers/monitoring/ThreadModule.java
+++ /dev/null
@@ -1,49 +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.functional.producers.monitoring;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.monitoring.ThreadQualifiers.Deferred;
-import dagger.functional.producers.monitoring.ThreadQualifiers.EntryPoint;
-import dagger.functional.producers.monitoring.ThreadQualifiers.Required;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-@ProducerModule
-final class ThreadModule {
- @Produces
- @Deferred
- Object deferred(ThreadAccumulator acc) {
- acc.markThread("deferred");
- return new Object();
- }
-
- @Produces
- @Required
- ListenableFuture<Object> required(@Deferred Producer<Object> o, ThreadAccumulator acc) {
- acc.markThread("required");
- return o.get();
- }
-
- @Produces
- @EntryPoint
- ThreadAccumulator entryPoint(@Required Object o, ThreadAccumulator acc) {
- acc.markThread("entryPoint");
- return acc;
- }
-}
diff --git a/javatests/dagger/functional/producers/monitoring/ThreadMonitoredComponent.java b/javatests/dagger/functional/producers/monitoring/ThreadMonitoredComponent.java
deleted file mode 100644
index 576cd7f..0000000
--- a/javatests/dagger/functional/producers/monitoring/ThreadMonitoredComponent.java
+++ /dev/null
@@ -1,30 +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.functional.producers.monitoring;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.functional.producers.monitoring.ThreadQualifiers.EntryPoint;
-import dagger.producers.ProductionComponent;
-import javax.inject.Singleton;
-
-@Singleton
-@ProductionComponent(modules = {ExecutorModule.class, MonitoringModule.class, ThreadModule.class})
-interface ThreadMonitoredComponent {
- @EntryPoint
- ListenableFuture<ThreadAccumulator> threadAccumulator();
-}
diff --git a/javatests/dagger/functional/producers/monitoring/ThreadQualifiers.java b/javatests/dagger/functional/producers/monitoring/ThreadQualifiers.java
deleted file mode 100644
index 59ccbe4..0000000
--- a/javatests/dagger/functional/producers/monitoring/ThreadQualifiers.java
+++ /dev/null
@@ -1,42 +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.functional.producers.monitoring;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-final class ThreadQualifiers {
- private ThreadQualifiers() {}
-
- @Qualifier
- @Retention(RUNTIME)
- @Documented
- @interface EntryPoint {}
-
- @Qualifier
- @Retention(RUNTIME)
- @Documented
- @interface Required {}
-
- @Qualifier
- @Retention(RUNTIME)
- @Documented
- @interface Deferred {}
-}
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java b/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
deleted file mode 100644
index fa5c6ee..0000000
--- a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
+++ /dev/null
@@ -1,81 +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.functional.producers.multibindings;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.functional.producers.multibindings.Qualifiers.EmptyButDeclaredInModule;
-import dagger.functional.producers.multibindings.Qualifiers.EmptyButDeclaredInModuleAndProducerModule;
-import dagger.functional.producers.multibindings.Qualifiers.ObjCount;
-import dagger.functional.producers.multibindings.Qualifiers.OnlyProvisionMultibindings;
-import dagger.functional.producers.multibindings.Qualifiers.PossiblyThrowingMap;
-import dagger.functional.producers.multibindings.Qualifiers.PossiblyThrowingSet;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProductionComponent;
-import java.util.Map;
-import java.util.Set;
-
-@ProductionComponent(
- modules = {ExecutorModule.class, MultibindingProducerModule.class, MultibindingModule.class}
-)
-interface MultibindingComponent {
- ListenableFuture<Set<String>> strs();
- ListenableFuture<Integer> strCount();
-
- ListenableFuture<Set<Produced<String>>> successfulSet();
-
- @PossiblyThrowingSet
- ListenableFuture<Set<Produced<String>>> possiblyThrowingSet();
-
- ListenableFuture<Map<Integer, String>> map();
-
- ListenableFuture<Map<Integer, Producer<String>>> mapOfProducer();
-
- ListenableFuture<Map<Integer, Produced<String>>> mapOfProduced();
-
- @PossiblyThrowingMap
- ListenableFuture<Map<Integer, String>> possiblyThrowingMap();
-
- @PossiblyThrowingMap
- ListenableFuture<Map<Integer, Producer<String>>> possiblyThrowingMapOfProducer();
-
- @PossiblyThrowingMap
- ListenableFuture<Map<Integer, Produced<String>>> possiblyThrowingMapOfProduced();
-
- ListenableFuture<Set<Object>> objs();
-
- ListenableFuture<Set<Produced<Object>>> producedObjs();
-
- ListenableFuture<Map<Object, Object>> objMap();
-
- ListenableFuture<Map<Object, Produced<Object>>> objMapOfProduced();
-
- ListenableFuture<Map<Object, Producer<Object>>> objMapOfProducer();
-
- @ObjCount
- ListenableFuture<Integer> objCount();
-
- @EmptyButDeclaredInModuleAndProducerModule
- ListenableFuture<Map<String, Object>> emptyButDeclaredInModuleAndProducerModule();
-
- @EmptyButDeclaredInModule
- ListenableFuture<Map<String, Object>> emptyButDeclaredInModule();
-
- @OnlyProvisionMultibindings
- ListenableFuture<Map<String, Object>> onlyProvisionMultibindings();
-}
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingModule.java b/javatests/dagger/functional/producers/multibindings/MultibindingModule.java
deleted file mode 100644
index 08ed6d7..0000000
--- a/javatests/dagger/functional/producers/multibindings/MultibindingModule.java
+++ /dev/null
@@ -1,70 +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.functional.producers.multibindings;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
-import dagger.functional.producers.multibindings.Qualifiers.EmptyButDeclaredInModule;
-import dagger.functional.producers.multibindings.Qualifiers.EmptyButDeclaredInModuleAndProducerModule;
-import dagger.functional.producers.multibindings.Qualifiers.OnlyProvisionMultibindings;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.multibindings.Multibinds;
-import dagger.multibindings.StringKey;
-import java.util.Map;
-import java.util.Set;
-
-@Module
-abstract class MultibindingModule {
- @Provides
- @IntoSet
- static String providedStr() {
- return "providedStr";
- }
-
- @Provides
- @ElementsIntoSet
- static Set<String> providedStrs() {
- return ImmutableSet.of("providedStr1", "providedStr2");
- }
-
- @Provides
- @IntoMap
- @IntKey(3)
- static String providedValueFor3() {
- return "provided three";
- }
-
- @Multibinds
- @EmptyButDeclaredInModuleAndProducerModule
- abstract Map<String, Object> emptyButDeclaredInModuleAndProducerModule();
-
- @Multibinds
- @EmptyButDeclaredInModule
- abstract Map<String, Object> emptyButDeclaredInModule();
-
- @Provides
- @IntoMap
- @StringKey("a")
- @OnlyProvisionMultibindings
- static Object onlyProvisionMultibindings() {
- return "only multibinding";
- }
-}
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java b/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java
deleted file mode 100644
index 350733b..0000000
--- a/javatests/dagger/functional/producers/multibindings/MultibindingProducerModule.java
+++ /dev/null
@@ -1,140 +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.functional.producers.multibindings;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.multibindings.Qualifiers.EmptyButDeclaredInModuleAndProducerModule;
-import dagger.functional.producers.multibindings.Qualifiers.ObjCount;
-import dagger.functional.producers.multibindings.Qualifiers.PossiblyThrowingMap;
-import dagger.functional.producers.multibindings.Qualifiers.PossiblyThrowingSet;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntKey;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produced;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.util.Map;
-import java.util.Set;
-
-@ProducerModule
-abstract class MultibindingProducerModule {
- @Produces
- @IntoSet
- static ListenableFuture<String> futureStr() {
- return Futures.immediateFuture("foo");
- }
-
- @Produces
- @IntoSet
- static String str() {
- return "bar";
- }
-
- @Produces
- @ElementsIntoSet
- static ListenableFuture<Set<String>> futureStrs() {
- return Futures.<Set<String>>immediateFuture(ImmutableSet.of("foo1", "foo2"));
- }
-
- @Produces
- @ElementsIntoSet
- static Set<ListenableFuture<String>> strFutures() {
- return ImmutableSet.of(Futures.immediateFuture("baz1"), Futures.immediateFuture("baz2"));
- }
-
- @Produces
- @ElementsIntoSet
- static Set<String> strs() {
- return ImmutableSet.of("bar1", "bar2");
- }
-
- @Produces
- static int strCount(Set<String> strs) {
- return strs.size();
- }
-
- @Produces
- @IntoSet
- @PossiblyThrowingSet
- static String successfulStringForSet() {
- return "singleton";
- }
-
- @Produces
- @ElementsIntoSet
- @PossiblyThrowingSet
- static Set<String> successfulStringsForSet() {
- return ImmutableSet.of("double", "ton");
- }
-
- @Produces
- @IntoSet
- @PossiblyThrowingSet
- static String throwingStringForSet() {
- throw new RuntimeException("monkey");
- }
-
- @Produces
- @IntoMap
- @IntKey(42)
- static ListenableFuture<String> futureFor42() {
- return Futures.immediateFuture("forty two");
- }
-
- @Produces
- @IntoMap
- @IntKey(15)
- static String valueFor15() {
- return "fifteen";
- }
-
- @Produces
- @IntoMap
- @PossiblyThrowingMap
- @IntKey(42)
- static ListenableFuture<String> successfulFutureFor42() {
- return Futures.immediateFuture("forty two");
- }
-
- @Produces
- @IntoMap
- @PossiblyThrowingMap
- @IntKey(15)
- static String throwingValueFor15() {
- throw new RuntimeException("monkey");
- }
-
- @Multibinds
- abstract Set<Object> objs();
-
- @Multibinds
- abstract Map<Object, Object> objMap();
-
- @Produces
- @ObjCount
- static int objCount(Set<Produced<Object>> objs, Map<Object, Produced<Object>> objMap) {
- return objs.size() + objMap.size();
- }
-
- @Multibinds
- @EmptyButDeclaredInModuleAndProducerModule
- abstract Map<String, Object> emptyButDeclaredInModuleAndProducerModule();
-}
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingTest.java b/javatests/dagger/functional/producers/multibindings/MultibindingTest.java
deleted file mode 100644
index 81daa88..0000000
--- a/javatests/dagger/functional/producers/multibindings/MultibindingTest.java
+++ /dev/null
@@ -1,189 +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.functional.producers.multibindings;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MultibindingTest {
- @Test
- public void setBinding() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- assertThat(multibindingComponent.strs().get())
- .containsExactly(
- "foo",
- "foo1",
- "foo2",
- "baz1",
- "baz2",
- "bar",
- "bar1",
- "bar2",
- "providedStr",
- "providedStr1",
- "providedStr2");
- assertThat(multibindingComponent.strCount().get()).isEqualTo(11);
- }
-
- @Test
- public void setBindingOfProduced() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- assertThat(multibindingComponent.successfulSet().get())
- .containsExactly(
- Produced.successful("foo"),
- Produced.successful("foo1"),
- Produced.successful("foo2"),
- Produced.successful("baz1"),
- Produced.successful("baz2"),
- Produced.successful("bar"),
- Produced.successful("bar1"),
- Produced.successful("bar2"),
- Produced.successful("providedStr"),
- Produced.successful("providedStr1"),
- Produced.successful("providedStr2"));
- }
-
- @Test
- public void setBindingOfProducedWithFailures() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Set<Produced<String>> possiblyThrowingSet = multibindingComponent.possiblyThrowingSet().get();
- Set<String> successes = new HashSet<>();
- Set<ExecutionException> failures = new HashSet<>();
- for (Produced<String> str : possiblyThrowingSet) {
- try {
- successes.add(str.get());
- } catch (ExecutionException e) {
- failures.add(e);
- }
- }
- assertThat(successes).containsExactly("singleton", "double", "ton");
- assertThat(failures).hasSize(1);
- assertThat(Iterables.getOnlyElement(failures).getCause()).hasMessageThat().isEqualTo("monkey");
- }
-
- @Test
- public void mapBinding() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Map<Integer, String> map = multibindingComponent.map().get();
- assertThat(map).hasSize(3);
- assertThat(map).containsEntry(15, "fifteen");
- assertThat(map).containsEntry(42, "forty two");
- assertThat(map).containsEntry(3, "provided three");
- }
-
- @Test
- public void mapOfProducerBinding() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Map<Integer, Producer<String>> map = multibindingComponent.mapOfProducer().get();
- assertThat(map).hasSize(3);
- assertThat(map).containsKey(15);
- assertThat(map.get(15).get().get()).isEqualTo("fifteen");
- assertThat(map).containsKey(42);
- assertThat(map.get(42).get().get()).isEqualTo("forty two");
- assertThat(map).containsKey(3);
- assertThat(map.get(3).get().get()).isEqualTo("provided three");
- }
-
- @Test
- public void mapOfProducedBinding() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Map<Integer, Produced<String>> map = multibindingComponent.mapOfProduced().get();
- assertThat(map).hasSize(3);
- assertThat(map).containsKey(15);
- assertThat(map.get(15).get()).isEqualTo("fifteen");
- assertThat(map).containsKey(42);
- assertThat(map.get(42).get()).isEqualTo("forty two");
- assertThat(map).containsKey(3);
- assertThat(map.get(3).get()).isEqualTo("provided three");
- }
-
- @Test
- public void mapBindingWithFailures() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- try {
- multibindingComponent.possiblyThrowingMap().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e.getCause()).hasMessageThat().isEqualTo("monkey");
- }
- }
-
- @Test
- public void mapOfProducerBindingWithFailures() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Map<Integer, Producer<String>> map =
- multibindingComponent.possiblyThrowingMapOfProducer().get();
- assertThat(map).hasSize(2);
- assertThat(map).containsKey(42);
- assertThat(map.get(42).get().get()).isEqualTo("forty two");
- assertThat(map).containsKey(15);
- ListenableFuture<String> future = map.get(15).get();
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e.getCause()).hasMessageThat().isEqualTo("monkey");
- }
- }
-
- @Test
- public void mapOfProducedBindingWithFailures() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- Map<Integer, Produced<String>> map =
- multibindingComponent.possiblyThrowingMapOfProduced().get();
- assertThat(map).hasSize(2);
- assertThat(map).containsKey(42);
- assertThat(map.get(42).get()).isEqualTo("forty two");
- assertThat(map).containsKey(15);
- Produced<String> produced = map.get(15);
- try {
- produced.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e.getCause()).hasMessageThat().isEqualTo("monkey");
- }
- }
-
- @Test
- public void emptySet() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- assertThat(multibindingComponent.objs().get()).isEmpty();
- assertThat(multibindingComponent.producedObjs().get()).isEmpty();
- assertThat(multibindingComponent.objCount().get()).isEqualTo(0);
- }
-
- @Test
- public void emptyMap() throws Exception {
- MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create();
- assertThat(multibindingComponent.objMap().get()).isEmpty();
- assertThat(multibindingComponent.objMapOfProduced().get()).isEmpty();
- assertThat(multibindingComponent.objMapOfProducer().get()).isEmpty();
- }
-}
diff --git a/javatests/dagger/functional/producers/multibindings/Qualifiers.java b/javatests/dagger/functional/producers/multibindings/Qualifiers.java
deleted file mode 100644
index 640430c..0000000
--- a/javatests/dagger/functional/producers/multibindings/Qualifiers.java
+++ /dev/null
@@ -1,57 +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.functional.producers.multibindings;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-final class Qualifiers {
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface PossiblyThrowingSet {}
-
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface PossiblyThrowingMap {}
-
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface ObjCount {}
-
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface EmptyButDeclaredInModule {}
-
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface EmptyButDeclaredInModuleAndProducerModule {}
-
- @Documented
- @Retention(RUNTIME)
- @Qualifier
- @interface OnlyProvisionMultibindings {}
-
- private Qualifiers() {}
-}
diff --git a/javatests/dagger/functional/producers/optional/OptionalBindingComponents.java b/javatests/dagger/functional/producers/optional/OptionalBindingComponents.java
deleted file mode 100644
index d3a7aa6..0000000
--- a/javatests/dagger/functional/producers/optional/OptionalBindingComponents.java
+++ /dev/null
@@ -1,199 +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.functional.producers.optional;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.Provides;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Retention;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import javax.annotation.Nullable;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-/** Classes to support testing {@code BindsOptionalOf} functionality. */
-final class OptionalBindingComponents {
-
- /** A qualifier. */
- @Qualifier
- @Retention(RUNTIME)
- @interface SomeQualifier {}
-
- /** A value object that contains various optionally-bound objects. */
- @AutoValue
- abstract static class Values {
- abstract Optional<Value> optionalInstance();
-
- abstract Optional<Producer<Value>> optionalProducer();
-
- abstract Optional<Produced<Value>> optionalProduced();
- }
-
- enum Value {
- VALUE,
- QUALIFIED_VALUE
- }
-
- @Module
- static final class ExecutorModule {
- @Provides
- @Production
- static Executor executor() {
- return Executors.newSingleThreadExecutor();
- }
- }
-
- /** Binds optionals and {@link Values}. */
- @ProducerModule
- abstract static class OptionalBindingModule {
- @BindsOptionalOf
- abstract Value value();
-
- @BindsOptionalOf
- @SomeQualifier
- abstract Value qualifiedValue();
-
- @BindsOptionalOf
- abstract Object nullableObject();
-
- @Produces
- static Values values(
- Optional<Value> optionalInstance,
- Optional<Producer<Value>> optionalProducer,
- Optional<Produced<Value>> optionalProduced) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProducer, optionalProduced);
- }
-
- @Produces
- @SomeQualifier
- static Values qualifiedValues(
- Optional<Value> optionalInstance,
- Optional<Producer<Value>> optionalProducer,
- Optional<Produced<Value>> optionalProduced) {
- return new AutoValue_OptionalBindingComponents_Values(
- optionalInstance, optionalProducer, optionalProduced);
- }
- }
-
- /** Binds {@link Value} using {@link Producer}s. */
- @ProducerModule
- abstract static class ConcreteBindingProducerModule {
- @Produces
- static Value value() {
- return Value.VALUE;
- }
-
- @Produces
- @SomeQualifier
- static Value qualifiedValue() {
- return Value.QUALIFIED_VALUE;
- }
-
- // @Produces @Nullable has no effect (and ProducesMethodValidator warns when the two are used
- // together. Use a @Provides method and let it be wrapped into a producerFromProvider for the
- // purposes of the test
- @Provides
- @Nullable
- static Object nullableObject() {
- return null;
- }
- }
-
- /** Binds {@link Value} using {@link Provider}s. */
- @Module
- abstract static class ConcreteBindingModule {
- @Provides
- static Value value() {
- return Value.VALUE;
- }
-
- @Provides
- @SomeQualifier
- static Value qualifiedValue() {
- return Value.QUALIFIED_VALUE;
- }
-
- @Provides
- @Nullable
- static Object nullableObject() {
- return null;
- }
- }
-
- interface OptionalBindingComponent {
- ListenableFuture<Values> values();
-
- ListenableFuture<Optional<Value>> optionalInstance();
-
- ListenableFuture<Optional<Producer<Value>>> optionalProducer();
-
- ListenableFuture<Optional<Produced<Value>>> optionalProduced();
-
- @SomeQualifier
- ListenableFuture<Values> qualifiedValues();
-
- @SomeQualifier
- ListenableFuture<Optional<Value>> qualifiedOptionalInstance();
-
- @SomeQualifier
- ListenableFuture<Optional<Producer<Value>>> qualifiedOptionalProducer();
-
- @SomeQualifier
- ListenableFuture<Optional<Produced<Value>>> qualifiedOptionalProduced();
-
- // Nullable bindings can satisfy optional bindings except for Optional<Foo>.
- ListenableFuture<Optional<Producer<Object>>> optionalNullableProducer();
-
- ListenableFuture<Optional<Produced<Object>>> optionalNullableProduced();
- }
-
- @ProductionComponent(modules = {ExecutorModule.class, OptionalBindingModule.class})
- interface AbsentOptionalBindingComponent extends OptionalBindingComponent {
- PresentOptionalBindingSubcomponent presentChild();
- }
-
- @ProductionComponent(
- modules = {
- ExecutorModule.class,
- OptionalBindingModule.class,
- ConcreteBindingProducerModule.class
- }
- )
- interface PresentOptionalBindingComponent extends OptionalBindingComponent {}
-
- @ProductionSubcomponent(modules = ConcreteBindingProducerModule.class)
- interface PresentOptionalBindingSubcomponent extends OptionalBindingComponent {}
-
- @ProductionComponent(
- modules = {ExecutorModule.class, OptionalBindingModule.class, ConcreteBindingModule.class}
- )
- interface PresentOptionalProvisionBindingComponent extends OptionalBindingComponent {}
-}
diff --git a/javatests/dagger/functional/producers/optional/OptionalBindingComponentsAbsentTest.java b/javatests/dagger/functional/producers/optional/OptionalBindingComponentsAbsentTest.java
deleted file mode 100644
index 4bb7234..0000000
--- a/javatests/dagger/functional/producers/optional/OptionalBindingComponentsAbsentTest.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.functional.producers.optional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.optional.OptionalBindingComponents.AbsentOptionalBindingComponent;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for absent optional bindings. */
-@RunWith(JUnit4.class)
-public final class OptionalBindingComponentsAbsentTest {
- private AbsentOptionalBindingComponent absent;
-
- @Before
- public void setUp() {
- absent = DaggerOptionalBindingComponents_AbsentOptionalBindingComponent.create();
- }
-
- @Test
- public void optional() throws Exception {
- assertThat(absent.optionalInstance().get()).isAbsent();
- }
-
- @Test
- public void optionalProducer() throws Exception {
- assertThat(absent.optionalProducer().get()).isAbsent();
- }
-
- @Test
- public void optionalProduced() throws Exception {
- assertThat(absent.optionalProduced().get()).isAbsent();
- }
-
- @Test
- public void qualifiedOptional() throws Exception {
- assertThat(absent.qualifiedOptionalInstance().get()).isAbsent();
- }
-
- @Test
- public void qualifiedOptionalProducer() throws Exception {
- assertThat(absent.qualifiedOptionalProducer().get()).isAbsent();
- }
-
- @Test
- public void qualifiedOptionalProduced() throws Exception {
- assertThat(absent.qualifiedOptionalProduced().get()).isAbsent();
- }
-}
diff --git a/javatests/dagger/functional/producers/optional/OptionalBindingComponentsPresentTest.java b/javatests/dagger/functional/producers/optional/OptionalBindingComponentsPresentTest.java
deleted file mode 100644
index 3e2afd4..0000000
--- a/javatests/dagger/functional/producers/optional/OptionalBindingComponentsPresentTest.java
+++ /dev/null
@@ -1,90 +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.functional.producers.optional;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.functional.producers.optional.OptionalBindingComponents.Value.QUALIFIED_VALUE;
-import static dagger.functional.producers.optional.OptionalBindingComponents.Value.VALUE;
-
-import com.google.common.collect.ImmutableList;
-import dagger.functional.producers.optional.OptionalBindingComponents.OptionalBindingComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for present optional bindings. */
-@RunWith(Parameterized.class)
-public final class OptionalBindingComponentsPresentTest {
-
- @Parameters(name = "{0}")
- public static Iterable<Object[]> parameters() {
- return ImmutableList.copyOf(
- new Object[][] {
- {DaggerOptionalBindingComponents_PresentOptionalBindingComponent.create()},
- {DaggerOptionalBindingComponents_AbsentOptionalBindingComponent.create().presentChild()},
- {DaggerOptionalBindingComponents_PresentOptionalProvisionBindingComponent.create()}
- });
- }
-
- private final OptionalBindingComponent component;
-
- public OptionalBindingComponentsPresentTest(OptionalBindingComponent component) {
- this.component = component;
- }
-
- @Test
- public void optional() throws Exception {
- assertThat(component.optionalInstance().get()).hasValue(VALUE);
- }
-
- @Test
- public void optionalProducer() throws Exception {
- assertThat(component.optionalProducer().get().get().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void optionalProduced() throws Exception {
- assertThat(component.optionalProduced().get().get().get()).isEqualTo(VALUE);
- }
-
- @Test
- public void qualifiedOptional() throws Exception {
- assertThat(component.qualifiedOptionalInstance().get()).hasValue(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalProducer() throws Exception {
- assertThat(component.qualifiedOptionalProducer().get().get().get().get())
- .isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void qualifiedOptionalProduced() throws Exception {
- assertThat(component.qualifiedOptionalProduced().get().get().get()).isEqualTo(QUALIFIED_VALUE);
- }
-
- @Test
- public void optionalNullableProducer() throws Exception {
- assertThat(component.optionalNullableProducer().get().get().get().get()).isNull();
- }
-
- @Test
- public void optionalNullableProduced() throws Exception {
- assertThat(component.optionalNullableProduced().get().get().get()).isNull();
- }
-}
diff --git a/javatests/dagger/functional/producers/provisions/Provisions.java b/javatests/dagger/functional/producers/provisions/Provisions.java
deleted file mode 100644
index 16f3337..0000000
--- a/javatests/dagger/functional/producers/provisions/Provisions.java
+++ /dev/null
@@ -1,80 +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.functional.producers.provisions;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-
-/** Tests for requesting provisions from producers. */
-final class Provisions {
- static final class InjectedClass {
- @Inject InjectedClass() {}
- }
-
- static final class WrappedProducer<T> {
- final Producer<T> producer;
-
- WrappedProducer(Producer<T> producer) {
- this.producer = producer;
- }
- }
-
- static final class Output {
- final Producer<InjectedClass> injectedClass1;
- final Producer<InjectedClass> injectedClass2;
-
- Output(Producer<InjectedClass> injectedClass1, Producer<InjectedClass> injectedClass2) {
- this.injectedClass1 = injectedClass1;
- this.injectedClass2 = injectedClass2;
- }
- }
-
- @Qualifier @interface First {}
- @Qualifier @interface Second {}
-
- @ProducerModule
- static final class TestModule {
- @Produces @First static WrappedProducer<InjectedClass> firstProducer(
- Producer<InjectedClass> injectedClass) {
- return new WrappedProducer<>(injectedClass);
- }
-
- @Produces @Second static WrappedProducer<InjectedClass> secondProducer(
- Producer<InjectedClass> injectedClass) {
- return new WrappedProducer<>(injectedClass);
- }
-
- @Produces static Output output(
- @First WrappedProducer<InjectedClass> producer1,
- @Second WrappedProducer<InjectedClass> producer2) {
- return new Output(producer1.producer, producer2.producer);
- }
- }
-
- @ProductionComponent(modules = {ExecutorModule.class, TestModule.class})
- interface TestComponent {
- ListenableFuture<Output> output();
- }
-
- private Provisions() {}
-}
diff --git a/javatests/dagger/functional/producers/provisions/ProvisionsTest.java b/javatests/dagger/functional/producers/provisions/ProvisionsTest.java
deleted file mode 100644
index 47ed2a2..0000000
--- a/javatests/dagger/functional/producers/provisions/ProvisionsTest.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.functional.producers.provisions;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.provisions.Provisions.Output;
-import dagger.functional.producers.provisions.Provisions.TestComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ProvisionsTest {
-
- @Test
- public void provisionsOnlyAreHeldInOneProducer() throws Exception {
- TestComponent component = DaggerProvisions_TestComponent.create();
- Output output = component.output().get();
- assertThat(output.injectedClass1).isSameInstanceAs(output.injectedClass2);
- }
-}
diff --git a/javatests/dagger/functional/producers/scope/ScopeTest.java b/javatests/dagger/functional/producers/scope/ScopeTest.java
deleted file mode 100644
index 9cfd2c2..0000000
--- a/javatests/dagger/functional/producers/scope/ScopeTest.java
+++ /dev/null
@@ -1,34 +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.functional.producers.scope;
-
-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 final class ScopeTest {
-
- @Test
- public void scope() throws Exception {
- SetComponent component = DaggerSetComponent.create();
- assertThat(component.set().get()).hasSize(1);
- assertThat(component.scopedObject()).isSameInstanceAs(component.scopedObject());
- }
-}
diff --git a/javatests/dagger/functional/producers/scope/ScopedModule.java b/javatests/dagger/functional/producers/scope/ScopedModule.java
deleted file mode 100644
index eec300b..0000000
--- a/javatests/dagger/functional/producers/scope/ScopedModule.java
+++ /dev/null
@@ -1,30 +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.functional.producers.scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.producers.ProductionScope;
-
-@Module
-final class ScopedModule {
- @Provides
- @ProductionScope
- static Object newScopedObject() {
- return new Object();
- }
-}
diff --git a/javatests/dagger/functional/producers/scope/ScopedObject.java b/javatests/dagger/functional/producers/scope/ScopedObject.java
deleted file mode 100644
index 07eebd9..0000000
--- a/javatests/dagger/functional/producers/scope/ScopedObject.java
+++ /dev/null
@@ -1,26 +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.functional.producers.scope;
-
-import dagger.producers.ProductionScope;
-import javax.inject.Inject;
-
-@ProductionScope
-final class ScopedObject {
- @Inject
- ScopedObject() {}
-}
diff --git a/javatests/dagger/functional/producers/scope/SetComponent.java b/javatests/dagger/functional/producers/scope/SetComponent.java
deleted file mode 100644
index 8400b70..0000000
--- a/javatests/dagger/functional/producers/scope/SetComponent.java
+++ /dev/null
@@ -1,29 +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.functional.producers.scope;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProductionComponent;
-import java.util.Set;
-
-@ProductionComponent(modules = {ExecutorModule.class, ScopedModule.class, SetProducerModule.class})
-interface SetComponent {
- ScopedObject scopedObject();
-
- ListenableFuture<Set<Object>> set();
-}
diff --git a/javatests/dagger/functional/producers/scope/SetProducerModule.java b/javatests/dagger/functional/producers/scope/SetProducerModule.java
deleted file mode 100644
index f88c91b..0000000
--- a/javatests/dagger/functional/producers/scope/SetProducerModule.java
+++ /dev/null
@@ -1,40 +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.functional.producers.scope;
-
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-/**
- * A module that provides two entries into a set; but since the inputs are scoped, the set should
- * only have one value.
- */
-@ProducerModule
-final class SetProducerModule {
- @Produces
- @IntoSet
- static Object setValue1(Object value) {
- return value;
- }
-
- @Produces
- @IntoSet
- static Object setValue2(Object value) {
- return value;
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/ModuleSubcomponentsInterop.java b/javatests/dagger/functional/producers/subcomponent/ModuleSubcomponentsInterop.java
deleted file mode 100644
index 673be2b..0000000
--- a/javatests/dagger/functional/producers/subcomponent/ModuleSubcomponentsInterop.java
+++ /dev/null
@@ -1,58 +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.functional.producers.subcomponent;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-
-final class ModuleSubcomponentsInterop {
- @Component(modules = ProvisionTestModule.class)
- interface ProvisionParent {
- ProductionChild.Builder productionChild();
- }
-
- @Module(subcomponents = ProductionChild.class)
- static class ProvisionTestModule {}
-
- @ProductionSubcomponent
- interface ProductionChild {
- @ProductionSubcomponent.Builder
- interface Builder {
- ProductionChild build();
- }
- }
-
- @ProductionComponent(modules = ProductionTestModule.class)
- interface ProductionParent {
- ProvisionChild.Builder provisionBuilder();
- }
-
- @ProducerModule(subcomponents = ProvisionChild.class)
- static class ProductionTestModule {}
-
- @Subcomponent
- interface ProvisionChild {
- @Subcomponent.Builder
- interface Builder {
- ProvisionChild build();
- }
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponentTest.java b/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponentTest.java
deleted file mode 100644
index 482991d..0000000
--- a/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponentTest.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.functional.producers.subcomponent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.subcomponent.MultiPackageSubcomponents.ParentComponent;
-import dagger.functional.producers.subcomponent.sub.ChildComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class MultiPackageSubcomponentTest {
-
- @Test
- public void childComponent() throws Exception {
- ParentComponent parent = DaggerMultiPackageSubcomponents_ParentComponent.create();
- ChildComponent child = parent.childComponentBuilder().build();
- assertThat(child.str().get()).isEqualTo("Hello, World 42");
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponents.java b/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponents.java
deleted file mode 100644
index 953bfff..0000000
--- a/javatests/dagger/functional/producers/subcomponent/MultiPackageSubcomponents.java
+++ /dev/null
@@ -1,39 +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.functional.producers.subcomponent;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.functional.producers.subcomponent.sub.ChildComponent;
-
-final class MultiPackageSubcomponents {
- @Component(modules = IntModule.class)
- interface ParentComponent {
- ChildComponent.Builder childComponentBuilder();
- }
-
- @Module
- static final class IntModule {
- @Provides
- static int i() {
- return 42;
- }
- }
-
- private MultiPackageSubcomponents() {}
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/ProducerModuleWithSubcomponentsTest.java b/javatests/dagger/functional/producers/subcomponent/ProducerModuleWithSubcomponentsTest.java
deleted file mode 100644
index 7568071..0000000
--- a/javatests/dagger/functional/producers/subcomponent/ProducerModuleWithSubcomponentsTest.java
+++ /dev/null
@@ -1,46 +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.functional.producers.subcomponent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.subcomponent.UsesProducerModuleSubcomponents.ParentIncludesProductionSubcomponentTransitively;
-import dagger.producers.ProducerModule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link ProducerModule#subcomponents()}. */
-@RunWith(JUnit4.class)
-public class ProducerModuleWithSubcomponentsTest {
-
- @Test
- public void subcomponentFromModules() throws Exception {
- UsesProducerModuleSubcomponents parent = DaggerUsesProducerModuleSubcomponents.create();
- assertThat(parent.strings().get()).containsExactly("from parent");
- assertThat(parent.stringsFromChild().get()).containsExactly("from parent", "from child");
- }
-
- @Test
- public void subcomponentFromModules_transitively() throws Exception {
- ParentIncludesProductionSubcomponentTransitively parent =
- DaggerUsesProducerModuleSubcomponents_ParentIncludesProductionSubcomponentTransitively
- .create();
- assertThat(parent.strings().get()).containsExactly("from parent");
- assertThat(parent.stringsFromChild().get()).containsExactly("from parent", "from child");
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/ProductionSubcomponentFromModuleAndFactoryMethod.java b/javatests/dagger/functional/producers/subcomponent/ProductionSubcomponentFromModuleAndFactoryMethod.java
deleted file mode 100644
index 1286247..0000000
--- a/javatests/dagger/functional/producers/subcomponent/ProductionSubcomponentFromModuleAndFactoryMethod.java
+++ /dev/null
@@ -1,46 +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.functional.producers.subcomponent;
-
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-
-/**
- * Tests for {@link Subcomponent}s which are defined with {@link Module#subcomponents()} and are
- * also requested as component factory methods.
- */
-public class ProductionSubcomponentFromModuleAndFactoryMethod {
- @ProductionSubcomponent
- interface Sub {
- @ProductionSubcomponent.Builder
- interface Builder {
- Sub sub();
- }
- }
-
- @ProducerModule(subcomponents = Sub.class)
- static class ModuleWithSubcomponent {}
-
- @ProductionComponent(modules = {ModuleWithSubcomponent.class, ExecutorModule.class})
- interface ExposesBuilder {
- Sub.Builder subcomponentBuilder();
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/SubcomponentWithBoundExecutorTest.java b/javatests/dagger/functional/producers/subcomponent/SubcomponentWithBoundExecutorTest.java
deleted file mode 100644
index 6d176d7..0000000
--- a/javatests/dagger/functional/producers/subcomponent/SubcomponentWithBoundExecutorTest.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.functional.producers.subcomponent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.ChildComponent;
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.ExecutorModule;
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.GrandchildComponent;
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.GrandchildComponentWithoutBuilder;
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.ParentComponent;
-import dagger.functional.producers.subcomponent.SubcomponentsWithBoundExecutor.ParentProductionComponent;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class SubcomponentWithBoundExecutorTest {
- private ParentComponent parentComponent;
- private ParentProductionComponent parentProductionComponent;
- private final AtomicInteger executorConstructionCount = new AtomicInteger();
- private final AtomicInteger executionCount = new AtomicInteger();
-
- @Before
- public void setUp() {
- parentComponent =
- DaggerSubcomponentsWithBoundExecutor_ParentComponent.builder()
- .executorModule(new ExecutorModule(executorConstructionCount, executionCount))
- .build();
- parentProductionComponent =
- DaggerSubcomponentsWithBoundExecutor_ParentProductionComponent.builder()
- .executorModule(new ExecutorModule(executorConstructionCount, executionCount))
- .build();
- }
-
- @Test
- public void topLevelComponent_child() throws Exception {
- ChildComponent child = parentComponent.newChildComponentBuilder().build();
- assertThat(child.fromChild().get()).isEqualTo("child:parent");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(1);
- }
-
- @Test
- public void topLevelComponent_injectsChildBuilder() throws Exception {
- ChildComponent child = parentComponent.injectsChildBuilder().childBuilder().build();
- assertThat(child.fromChild().get()).isEqualTo("child:parent");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(1);
- }
-
- @Test
- public void topLevelComponent_grandchild() throws Exception {
- ChildComponent child = parentComponent.newChildComponentBuilder().build();
- GrandchildComponent grandchild = child.newGrandchildComponentBuilder().build();
- assertThat(grandchild.fromGrandchild().get()).isEqualTo("grandchild:child:parent");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(2);
- }
-
- @Test
- public void topLevelComponent_grandchildWithoutBuilder() throws Exception {
- ChildComponent child = parentComponent.newChildComponentBuilder().build();
- GrandchildComponentWithoutBuilder grandchild = child.newGrandchildComponent();
- assertThat(grandchild.fromGrandchild().get()).isEqualTo("grandchild:child:parent");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(2);
- }
-
- @Test
- public void topLevelProductionComponent_child() throws Exception {
- ChildComponent child = parentProductionComponent.newChildComponentBuilder().build();
- assertThat(child.fromChild().get()).isEqualTo("child:parentproduction");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(2);
- }
-
- @Test
- public void topLevelProductionComponent_grandchild() throws Exception {
- ChildComponent child = parentProductionComponent.newChildComponentBuilder().build();
- GrandchildComponent grandchild = child.newGrandchildComponentBuilder().build();
- assertThat(grandchild.fromGrandchild().get()).isEqualTo("grandchild:child:parentproduction");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(3);
- }
-
- @Test
- public void topLevelProductionComponent_grandchildWithoutBuilder() throws Exception {
- ChildComponent child = parentProductionComponent.newChildComponentBuilder().build();
- GrandchildComponentWithoutBuilder grandchild = child.newGrandchildComponent();
- assertThat(grandchild.fromGrandchild().get()).isEqualTo("grandchild:child:parentproduction");
- assertThat(executorConstructionCount.get()).isEqualTo(1);
- assertThat(executionCount.get()).isEqualTo(3);
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java b/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java
deleted file mode 100644
index f7059c7..0000000
--- a/javatests/dagger/functional/producers/subcomponent/SubcomponentsWithBoundExecutor.java
+++ /dev/null
@@ -1,176 +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.functional.producers.subcomponent;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.Production;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Qualifier;
-
-final class SubcomponentsWithBoundExecutor {
- @Qualifier
- @interface FromParent {}
-
- @Qualifier
- @interface FromChild {}
-
- @Qualifier
- @interface FromGrandchild {}
-
- static final class CountingExecutor implements Executor {
- private final AtomicInteger executionCount;
-
- CountingExecutor(AtomicInteger executionCount) {
- this.executionCount = executionCount;
- }
-
- @Override
- public void execute(Runnable runnable) {
- executionCount.incrementAndGet();
- runnable.run();
- }
- }
-
- @Module
- static final class ExecutorModule {
- private final AtomicInteger constructionCount;
- private final AtomicInteger executionCount;
-
- ExecutorModule(AtomicInteger constructionCount, AtomicInteger executionCount) {
- this.constructionCount = constructionCount;
- this.executionCount = executionCount;
- }
-
- @Provides
- @Production
- Executor executor() {
- constructionCount.incrementAndGet();
- return new CountingExecutor(executionCount);
- }
- }
-
- @Module
- static final class ParentModule {
- @Provides
- @FromParent
- static String fromParent() {
- return "parent";
- }
- }
-
- @Component(modules = {ParentModule.class, ExecutorModule.class})
- interface ParentComponent {
- InjectsChildBuilder injectsChildBuilder();
-
- ChildComponent.Builder newChildComponentBuilder();
- }
-
- @ProducerModule
- static final class ParentProducerModule {
- @Produces
- @FromParent
- static String fromParent() {
- return "parentproduction";
- }
- }
-
- @ProductionComponent(modules = {ParentProducerModule.class, ExecutorModule.class})
- interface ParentProductionComponent {
- ChildComponent.Builder newChildComponentBuilder();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder executorModule(ExecutorModule executorModule);
-
- ParentProductionComponent build();
- }
- }
-
- @ProducerModule
- static final class ChildProducerModule {
- @Produces
- @FromChild
- static String fromChild(@FromParent String fromParent) {
- return "child:" + fromParent;
- }
- }
-
- @ProductionSubcomponent(modules = ChildProducerModule.class)
- interface ChildComponent {
- @FromChild
- ListenableFuture<String> fromChild();
-
- GrandchildComponent.Builder newGrandchildComponentBuilder();
- GrandchildComponentWithoutBuilder newGrandchildComponent();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- ChildComponent build();
- }
- }
-
- static final class InjectsChildBuilder {
- private final Provider<ChildComponent.Builder> childBuilder;
-
- @Inject
- InjectsChildBuilder(Provider<ChildComponent.Builder> childBuilder) {
- this.childBuilder = childBuilder;
- }
-
- ChildComponent.Builder childBuilder() {
- return childBuilder.get();
- }
- }
-
- @ProducerModule
- static final class GrandchildProducerModule {
- @Produces
- @FromGrandchild
- static String fromGranchild(@FromChild String fromChild) {
- return "grandchild:" + fromChild;
- }
- }
-
- @ProductionSubcomponent(modules = GrandchildProducerModule.class)
- interface GrandchildComponent {
- @FromGrandchild
- ListenableFuture<String> fromGrandchild();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- GrandchildComponent build();
- }
- }
-
- @ProductionSubcomponent(modules = GrandchildProducerModule.class)
- interface GrandchildComponentWithoutBuilder {
- @FromGrandchild
- ListenableFuture<String> fromGrandchild();
- }
-
- private SubcomponentsWithBoundExecutor() {}
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/UsesProducerModuleSubcomponents.java b/javatests/dagger/functional/producers/subcomponent/UsesProducerModuleSubcomponents.java
deleted file mode 100644
index 31253cc..0000000
--- a/javatests/dagger/functional/producers/subcomponent/UsesProducerModuleSubcomponents.java
+++ /dev/null
@@ -1,89 +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.functional.producers.subcomponent;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.util.Set;
-import javax.inject.Qualifier;
-
-/** Supporting types for {@code ProducerModuleWithSubcomponentsTest}. */
-@ProductionComponent(
- modules = UsesProducerModuleSubcomponents.ProducerModuleWithSubcomponents.class
-)
-public interface UsesProducerModuleSubcomponents {
-
- ListenableFuture<Set<String>> strings();
-
- @FromChild
- ListenableFuture<Set<String>> stringsFromChild();
-
- @ProducerModule(
- subcomponents = Child.class,
- includes = {AlsoIncludesSubcomponents.class, ExecutorModule.class}
- )
- class ProducerModuleWithSubcomponents {
- @Produces
- @IntoSet
- static String produceStringInParent() {
- return "from parent";
- }
-
- @Produces
- @FromChild
- static Set<String> stringsFromChild(Child.Builder childBuilder) throws Exception {
- return childBuilder.build().strings().get();
- }
- }
-
- @ProducerModule(subcomponents = Child.class)
- class AlsoIncludesSubcomponents {}
-
- @ProductionSubcomponent(modules = ChildModule.class)
- interface Child {
- ListenableFuture<Set<String>> strings();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- Child build();
- }
- }
-
- @ProducerModule
- class ChildModule {
- @Produces
- @IntoSet
- static String produceStringInChild() {
- return "from child";
- }
- }
-
- @Qualifier
- @interface FromChild {}
-
- @ProducerModule(includes = ProducerModuleWithSubcomponents.class)
- class OnlyIncludesProducerModuleWithSubcomponents {}
-
- @ProductionComponent(modules = OnlyIncludesProducerModuleWithSubcomponents.class)
- interface ParentIncludesProductionSubcomponentTransitively
- extends UsesProducerModuleSubcomponents {}
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/pruning/ParentDoesntUseProductionSubcomponent.java b/javatests/dagger/functional/producers/subcomponent/pruning/ParentDoesntUseProductionSubcomponent.java
deleted file mode 100644
index bf931c1..0000000
--- a/javatests/dagger/functional/producers/subcomponent/pruning/ParentDoesntUseProductionSubcomponent.java
+++ /dev/null
@@ -1,101 +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.functional.producers.subcomponent.pruning;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.util.Set;
-import javax.inject.Qualifier;
-
-/**
- * Supporting types for {@code ProductionSubcomponentOnlyRequestedBySiblingTest}. {@link ChildA} is
- * a direct child of the top level component, but is only requested within its sibling, not directly
- * from its parent.
- */
-@ProductionComponent(
- modules = {
- ParentDoesntUseProductionSubcomponent.ParentModule.class,
- dagger.functional.producers.ExecutorModule.class
- }
-)
-interface ParentDoesntUseProductionSubcomponent {
-
- ChildB.Builder childBBuilder();
-
- @ProductionSubcomponent(modules = ChildAModule.class)
- interface ChildA {
- @ProductionSubcomponent.Builder
- interface Builder {
- ChildA build();
- }
-
- ListenableFuture<Set<Class<?>>> componentHierarchy();
- }
-
- @ProductionSubcomponent(modules = ChildBModule.class)
- interface ChildB {
- @ProductionSubcomponent.Builder
- interface Builder {
- ChildB build();
- }
-
- ListenableFuture<Set<Class<?>>> componentHierarchy();
-
- @FromChildA
- ListenableFuture<Set<Class<?>>> componentHierarchyFromChildA();
- }
-
- @ProducerModule(subcomponents = {ChildA.class, ChildB.class})
- class ParentModule {
- @Produces
- @IntoSet
- static Class<?> produceComponentType() {
- return ParentDoesntUseProductionSubcomponent.class;
- }
- }
-
- @ProducerModule
- class ChildAModule {
- @Produces
- @IntoSet
- static Class<?> produceComponentType() {
- return ChildA.class;
- }
- }
-
- @ProducerModule
- class ChildBModule {
- @Produces
- @IntoSet
- static Class<?> produceComponentType() {
- return ChildB.class;
- }
-
- @Produces
- @FromChildA
- Set<Class<?>> fromChildA(ChildA.Builder childABuilder) throws Exception {
- return childABuilder.build().componentHierarchy().get();
- }
- }
-
- @Qualifier
- @interface FromChildA {}
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/pruning/ProductionSubcomponentOnlyRequestedBySiblingTest.java b/javatests/dagger/functional/producers/subcomponent/pruning/ProductionSubcomponentOnlyRequestedBySiblingTest.java
deleted file mode 100644
index d178061..0000000
--- a/javatests/dagger/functional/producers/subcomponent/pruning/ProductionSubcomponentOnlyRequestedBySiblingTest.java
+++ /dev/null
@@ -1,50 +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.functional.producers.subcomponent.pruning;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.functional.producers.subcomponent.pruning.ParentDoesntUseProductionSubcomponent.ChildA;
-import dagger.functional.producers.subcomponent.pruning.ParentDoesntUseProductionSubcomponent.ChildB;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionSubcomponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for {@link ProductionSubcomponent}s which are included with {@link
- * ProducerModule#subcomponents()} but not used directly within the component which adds them.
- *
- * <p>This tests to make sure that while resolving one subcomponent (A), another subcomponent (B)
- * can be requested if they have a shared ancestor component. If that shared ancestor did not
- * resolve B directly via any of its entry points, B will still be generated since it is requested
- * by a descendant.
- */
-@RunWith(JUnit4.class)
-public class ProductionSubcomponentOnlyRequestedBySiblingTest {
- @Test
- public void subcomponentAddedInParent_onlyUsedInSibling() throws Exception {
- ParentDoesntUseProductionSubcomponent parent =
- DaggerParentDoesntUseProductionSubcomponent.create();
- ChildB childB = parent.childBBuilder().build();
- assertThat(childB.componentHierarchy().get())
- .containsExactly(ParentDoesntUseProductionSubcomponent.class, ChildB.class);
- assertThat(childB.componentHierarchyFromChildA().get())
- .containsExactly(ParentDoesntUseProductionSubcomponent.class, ChildA.class);
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/sub/ChildComponent.java b/javatests/dagger/functional/producers/subcomponent/sub/ChildComponent.java
deleted file mode 100644
index 4dfb112..0000000
--- a/javatests/dagger/functional/producers/subcomponent/sub/ChildComponent.java
+++ /dev/null
@@ -1,31 +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.functional.producers.subcomponent.sub;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.functional.producers.ExecutorModule;
-import dagger.producers.ProductionSubcomponent;
-
-@ProductionSubcomponent(modules = {ExecutorModule.class, ChildModule.class})
-public interface ChildComponent {
- ListenableFuture<String> str();
-
- @ProductionSubcomponent.Builder
- interface Builder {
- ChildComponent build();
- }
-}
diff --git a/javatests/dagger/functional/producers/subcomponent/sub/ChildModule.java b/javatests/dagger/functional/producers/subcomponent/sub/ChildModule.java
deleted file mode 100644
index 8994a8a..0000000
--- a/javatests/dagger/functional/producers/subcomponent/sub/ChildModule.java
+++ /dev/null
@@ -1,28 +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.functional.producers.subcomponent.sub;
-
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-
-@ProducerModule
-final class ChildModule {
- @Produces
- static String str(int n) {
- return "Hello, World " + n;
- }
-}
diff --git a/javatests/dagger/functional/rawtypes/RawTypesComponent.java b/javatests/dagger/functional/rawtypes/RawTypesComponent.java
deleted file mode 100644
index e2c69c2..0000000
--- a/javatests/dagger/functional/rawtypes/RawTypesComponent.java
+++ /dev/null
@@ -1,28 +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.functional.rawtypes;
-
-import dagger.Component;
-import java.util.Map;
-import java.util.Set;
-
-@SuppressWarnings("rawtypes")
-@Component(modules = RawtypesModule.class)
-interface RawTypesComponent {
- Set rawSet();
- Map rawMap();
-}
diff --git a/javatests/dagger/functional/rawtypes/RawtypesModule.java b/javatests/dagger/functional/rawtypes/RawtypesModule.java
deleted file mode 100644
index 3bf5f59..0000000
--- a/javatests/dagger/functional/rawtypes/RawtypesModule.java
+++ /dev/null
@@ -1,38 +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.functional.rawtypes;
-
-import dagger.Module;
-import dagger.Provides;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-@SuppressWarnings("rawtypes")
-@Module
-abstract class RawtypesModule {
- @Provides
- static Map rawMap() {
- return new HashMap();
- }
-
- @Provides
- static Set rawSet() {
- return new HashSet();
- }
-}
diff --git a/javatests/dagger/functional/scope/BlueModule.java b/javatests/dagger/functional/scope/BlueModule.java
deleted file mode 100644
index e04bc7a..0000000
--- a/javatests/dagger/functional/scope/BlueModule.java
+++ /dev/null
@@ -1,31 +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.functional.scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class BlueModule {
- @Provides
- @IntoSet
- @BlueScope
- static Object blue() {
- return new Object();
- }
-}
diff --git a/javatests/dagger/functional/scope/BlueScope.java b/javatests/dagger/functional/scope/BlueScope.java
deleted file mode 100644
index ecd0da5..0000000
--- a/javatests/dagger/functional/scope/BlueScope.java
+++ /dev/null
@@ -1,28 +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.functional.scope;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-@Documented
-@Retention(RUNTIME)
-@Scope
-@interface BlueScope {}
diff --git a/javatests/dagger/functional/scope/GreenModule.java b/javatests/dagger/functional/scope/GreenModule.java
deleted file mode 100644
index 3f9248f..0000000
--- a/javatests/dagger/functional/scope/GreenModule.java
+++ /dev/null
@@ -1,31 +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.functional.scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class GreenModule {
- @Provides
- @IntoSet
- @GreenScope
- static Object green() {
- return new Object();
- }
-}
diff --git a/javatests/dagger/functional/scope/GreenScope.java b/javatests/dagger/functional/scope/GreenScope.java
deleted file mode 100644
index 92bcc62..0000000
--- a/javatests/dagger/functional/scope/GreenScope.java
+++ /dev/null
@@ -1,28 +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.functional.scope;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-@Documented
-@Retention(RUNTIME)
-@Scope
-@interface GreenScope {}
diff --git a/javatests/dagger/functional/scope/ScopeTest.java b/javatests/dagger/functional/scope/ScopeTest.java
deleted file mode 100644
index 40c1fa9..0000000
--- a/javatests/dagger/functional/scope/ScopeTest.java
+++ /dev/null
@@ -1,34 +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.functional.scope;
-
-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 final class ScopeTest {
-
- @Test
- public void testScope() {
- ScopedComponent component = DaggerScopedComponent.create();
- assertThat(component.set()).hasSize(4);
- assertThat(component.set()).isEqualTo(component.set());
- }
-}
diff --git a/javatests/dagger/functional/scope/ScopedComponent.java b/javatests/dagger/functional/scope/ScopedComponent.java
deleted file mode 100644
index fa9b0da..0000000
--- a/javatests/dagger/functional/scope/ScopedComponent.java
+++ /dev/null
@@ -1,27 +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.functional.scope;
-
-import dagger.Component;
-import java.util.Set;
-
-@BlueScope
-@GreenScope
-@Component(modules = {BlueModule.class, GreenModule.class, TurquoiseModule.class})
-interface ScopedComponent {
- Set<Object> set();
-}
diff --git a/javatests/dagger/functional/scope/TurquoiseModule.java b/javatests/dagger/functional/scope/TurquoiseModule.java
deleted file mode 100644
index 780ecb2..0000000
--- a/javatests/dagger/functional/scope/TurquoiseModule.java
+++ /dev/null
@@ -1,38 +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.functional.scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class TurquoiseModule {
- @Provides
- @IntoSet
- @BlueScope
- static Object blue() {
- return new Object();
- }
-
- @Provides
- @IntoSet
- @GreenScope
- static Object green() {
- return new Object();
- }
-}
diff --git a/javatests/dagger/functional/spi/BUILD b/javatests/dagger/functional/spi/BUILD
deleted file mode 100644
index fffaddb..0000000
--- a/javatests/dagger/functional/spi/BUILD
+++ /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.
-
-# Description:
-# Functional tests for the experimental Dagger SPI
-
-package(default_visibility = ["//:src"])
-
-load("//:test_defs.bzl", "GenJavaTests")
-
-java_plugin(
- name = "test_plugin",
- srcs = ["TestPlugin.java"],
- deps = [
- "//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",
- ],
-)
-
-java_library(
- name = "test_lib",
- exported_plugins = [":test_plugin"],
-)
-
-GenJavaTests(
- name = "tests",
- srcs = glob(
- ["*.java"],
- exclude = ["TestPlugin.java"],
- ),
- functional = 0,
- test_only_deps = [
- "@google_bazel_common//third_party/java/truth",
- "@google_bazel_common//third_party/java/junit",
- ],
- deps = [
- ":test_lib",
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/guava",
- ],
-)
diff --git a/javatests/dagger/functional/spi/SpiTest.java b/javatests/dagger/functional/spi/SpiTest.java
deleted file mode 100644
index 05495e5..0000000
--- a/javatests/dagger/functional/spi/SpiTest.java
+++ /dev/null
@@ -1,56 +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.functional.spi;
-
-import static com.google.common.io.Resources.getResource;
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SpiTest {
-
- @Component(modules = M.class)
- interface C {
- String string();
- }
-
- @Module
- abstract static class M {
- @Provides
- static String string() {
- return "string";
- }
- }
-
- @Test
- public void testPluginRuns() throws IOException {
- Properties properties = new Properties();
- try (InputStream stream = getResource(SpiTest.class, "SpiTest_C.properties").openStream()) {
- properties.load(stream);
- }
- assertThat(properties).containsEntry("component[0]", C.class.getCanonicalName());
- }
-}
diff --git a/javatests/dagger/functional/spi/TestPlugin.java b/javatests/dagger/functional/spi/TestPlugin.java
deleted file mode 100644
index 360bc20..0000000
--- a/javatests/dagger/functional/spi/TestPlugin.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.functional.spi;
-
-import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
-import com.google.auto.service.AutoService;
-import com.google.common.base.Joiner;
-import com.squareup.javapoet.ClassName;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.io.Writer;
-import java.util.Properties;
-import javax.annotation.processing.Filer;
-
-@AutoService(BindingGraphPlugin.class)
-public final class TestPlugin implements BindingGraphPlugin {
- private Filer filer;
-
- @Override
- public void initFiler(Filer filer) {
- this.filer = filer;
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- Properties properties = new Properties();
- int i = 0;
- for (ComponentNode node : bindingGraph.componentNodes()) {
- properties.setProperty(
- String.format("component[%s]", i++), node.componentPath().toString());
- }
-
- write(bindingGraph, properties);
- }
-
- private void write(BindingGraph bindingGraph, Properties properties) {
- ClassName rootComponentName =
- ClassName.get(bindingGraph.rootComponentNode().componentPath().currentComponent());
- try (Writer writer =
- filer
- .createResource(
- CLASS_OUTPUT,
- rootComponentName.packageName(),
- Joiner.on('_').join(rootComponentName.simpleNames()) + ".properties")
- .openWriter()) {
- properties.store(writer, "");
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-}
diff --git a/javatests/dagger/functional/staticprovides/AllStaticModule.java b/javatests/dagger/functional/staticprovides/AllStaticModule.java
deleted file mode 100644
index fff63ee..0000000
--- a/javatests/dagger/functional/staticprovides/AllStaticModule.java
+++ /dev/null
@@ -1,40 +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.functional.staticprovides;
-
-import static java.util.Collections.emptySet;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoSet;
-import java.util.Set;
-
-@Module
-final class AllStaticModule {
- @Provides
- @IntoSet
- static String contributeString() {
- return AllStaticModule.class + ".contributeString";
- }
-
- @Provides
- @ElementsIntoSet
- static Set<Integer> contibuteEmptyIntegerSet() {
- return emptySet();
- }
-}
diff --git a/javatests/dagger/functional/staticprovides/SomeStaticModule.java b/javatests/dagger/functional/staticprovides/SomeStaticModule.java
deleted file mode 100644
index ab65b58..0000000
--- a/javatests/dagger/functional/staticprovides/SomeStaticModule.java
+++ /dev/null
@@ -1,36 +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.functional.staticprovides;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class SomeStaticModule {
- @Provides
- @IntoSet
- static String contributeStringFromAStaticMethod() {
- return SomeStaticModule.class + ".contributeStringFromAStaticMethod";
- }
-
- @Provides
- @IntoSet
- static String contributeStringFromAnInstanceMethod() {
- return SomeStaticModule.class + ".contributeStringFromAnInstanceMethod";
- }
-}
diff --git a/javatests/dagger/functional/staticprovides/StaticProvidesTest.java b/javatests/dagger/functional/staticprovides/StaticProvidesTest.java
deleted file mode 100644
index 9d9952a..0000000
--- a/javatests/dagger/functional/staticprovides/StaticProvidesTest.java
+++ /dev/null
@@ -1,72 +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.functional.staticprovides;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import com.google.common.collect.ImmutableSet;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collection;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class StaticProvidesTest {
- @Parameters
- public static Collection<Object[]> components() {
- return Arrays.asList(new Object[][] {
- {DaggerStaticTestComponent.create()},
- {DaggerStaticTestComponentWithBuilder.builder().build()},
- {DaggerStaticTestComponentWithBuilder.builder()
- .allStaticModule(new AllStaticModule())
- .someStaticModule(new SomeStaticModule())
- .build()}});
- }
-
- @Parameter
- public StaticTestComponent component;
-
- @Test public void setMultibinding() {
- assertThat(component.getMultiboundStrings()).isEqualTo(ImmutableSet.of(
- AllStaticModule.class + ".contributeString",
- SomeStaticModule.class + ".contributeStringFromAStaticMethod",
- SomeStaticModule.class + ".contributeStringFromAnInstanceMethod"));
- }
-
- @Test public void allStaticProvidesModules_noFieldInComponentBuilder() {
- for (Field field : DaggerStaticTestComponent.Builder.class.getDeclaredFields()) {
- assertWithMessage(field.getName())
- .that(field.getType()).isNotEqualTo(AllStaticModule.class);
- }
- }
-
- @Test public void allStaticProvidesModules_deprecatedMethodInComponentBuilder() {
- for (Method method : DaggerStaticTestComponent.Builder.class.getDeclaredMethods()) {
- if (Arrays.asList(method.getParameterTypes()).contains(AllStaticModule.class)) {
- assertWithMessage(method.getName())
- .that(method.isAnnotationPresent(Deprecated.class))
- .isTrue();
- }
- }
- }
-}
diff --git a/javatests/dagger/functional/staticprovides/StaticTestComponent.java b/javatests/dagger/functional/staticprovides/StaticTestComponent.java
deleted file mode 100644
index 4dced91..0000000
--- a/javatests/dagger/functional/staticprovides/StaticTestComponent.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.functional.staticprovides;
-
-import dagger.Component;
-import java.util.Set;
-
-/**
- * A simple component that demonstrates both static and non-static provides methods.
- */
-@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
-interface StaticTestComponent {
- Set<String> getMultiboundStrings();
- Set<Integer> getMultiboundIntegers();
-}
diff --git a/javatests/dagger/functional/staticprovides/StaticTestComponentWithBuilder.java b/javatests/dagger/functional/staticprovides/StaticTestComponentWithBuilder.java
deleted file mode 100644
index c6e8f2a..0000000
--- a/javatests/dagger/functional/staticprovides/StaticTestComponentWithBuilder.java
+++ /dev/null
@@ -1,32 +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.functional.staticprovides;
-
-import dagger.Component;
-
-/**
- * A simple component that demonstrates both static and non-static provides methods with a builder.
- */
-@Component(modules = {AllStaticModule.class, SomeStaticModule.class})
-interface StaticTestComponentWithBuilder extends StaticTestComponent {
- @Component.Builder
- interface Builder {
- Builder allStaticModule(AllStaticModule allStaticModule);
- Builder someStaticModule(SomeStaticModule someStaticModule);
- StaticTestComponentWithBuilder build();
- }
-}
diff --git a/javatests/dagger/functional/sub/ContributionsModule.java b/javatests/dagger/functional/sub/ContributionsModule.java
deleted file mode 100644
index 654e8f7..0000000
--- a/javatests/dagger/functional/sub/ContributionsModule.java
+++ /dev/null
@@ -1,47 +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.functional.sub;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoSet;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-@Module
-public final class ContributionsModule {
- @Provides
- @IntoSet
- static int contributeAnInt(@SuppressWarnings("unused") double doubleDependency) {
- return 1742;
- }
-
- @Provides
- @IntoSet
- static int contributeAnotherInt() {
- return 832;
- }
-
- @Provides
- @ElementsIntoSet
- static Set<Integer> contributeSomeInts() {
- return Collections.unmodifiableSet(new LinkedHashSet<Integer>(Arrays.asList(-1, -90, -17)));
- }
-}
diff --git a/javatests/dagger/functional/sub/Exposed.java b/javatests/dagger/functional/sub/Exposed.java
deleted file mode 100644
index 55c2d15..0000000
--- a/javatests/dagger/functional/sub/Exposed.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.functional.sub;
-
-import dagger.Lazy;
-import dagger.functional.Generic;
-import dagger.functional.Generic2;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-public class Exposed {
-
- @Inject public PackagePrivate pp2;
- @Inject public Provider<PackagePrivate> ppp2;
- @Inject public Lazy<PackagePrivate> lpp2;
- @Inject public Provider<Lazy<PackagePrivate>> plpp2;
- @Inject public Generic2<PackagePrivate> gpp2;
- @Inject public Generic2<PackagePrivateContainer.PublicEnclosed> gppc2;
- @Inject public Provider<Generic2<PackagePrivate>> pgpp2;
- @Inject public Lazy<Generic2<PackagePrivate>> lgpp2;
- @Inject public Provider<Lazy<Generic2<PackagePrivate>>> plgpp2;
-
- public PackagePrivate pp;
- public Provider<PackagePrivate> ppp;
- public Lazy<PackagePrivate> lpp;
- public Provider<Lazy<PackagePrivate>> plpp;
- public Generic<PackagePrivate> gpp;
- public Generic<PackagePrivateContainer.PublicEnclosed> gppc;
- public Provider<Generic<PackagePrivate>> pgpp;
- public Lazy<Generic<PackagePrivate>> lgpp;
- public Provider<Lazy<Generic<PackagePrivate>>> plgpp;
-
- /** Injects inaccessible dependencies to test casting of these dependency arguments. */
- @Inject Exposed(
- PackagePrivate pp,
- Provider<PackagePrivate> ppp,
- Lazy<PackagePrivate> lpp,
- Provider<Lazy<PackagePrivate>> plpp,
- Generic<PackagePrivate> gpp,
- Generic<PackagePrivateContainer.PublicEnclosed> gppc,
- Provider<Generic<PackagePrivate>> pgpp,
- Lazy<Generic<PackagePrivate>> lgpp,
- Provider<Lazy<Generic<PackagePrivate>>> plgpp) {
- this.pp = pp;
- this.ppp = ppp;
- this.lpp = lpp;
- this.plpp = plpp;
- this.gpp = gpp;
- this.gppc = gppc;
- this.pgpp = pgpp;
- this.lgpp = lgpp;
- this.plgpp = plgpp;
- }
-}
diff --git a/javatests/dagger/functional/sub/OtherThing.java b/javatests/dagger/functional/sub/OtherThing.java
deleted file mode 100644
index 9150aab..0000000
--- a/javatests/dagger/functional/sub/OtherThing.java
+++ /dev/null
@@ -1,24 +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.functional.sub;
-
-import javax.inject.Inject;
-
-public final class OtherThing {
- @Inject
- public OtherThing(@SuppressWarnings("unused") int i) {}
-}
diff --git a/javatests/dagger/functional/sub/PackagePrivate.java b/javatests/dagger/functional/sub/PackagePrivate.java
deleted file mode 100644
index 8220877..0000000
--- a/javatests/dagger/functional/sub/PackagePrivate.java
+++ /dev/null
@@ -1,23 +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.functional.sub;
-
-import javax.inject.Inject;
-
-class PackagePrivate {
- @Inject PackagePrivate() {}
-}
diff --git a/javatests/dagger/functional/sub/PackagePrivateContainer.java b/javatests/dagger/functional/sub/PackagePrivateContainer.java
deleted file mode 100644
index f1b1033..0000000
--- a/javatests/dagger/functional/sub/PackagePrivateContainer.java
+++ /dev/null
@@ -1,25 +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.functional.sub;
-
-import javax.inject.Inject;
-
-class PackagePrivateContainer {
- public static class PublicEnclosed {
- @Inject PublicEnclosed() {}
- }
-}
diff --git a/javatests/dagger/functional/sub/PublicSubclass.java b/javatests/dagger/functional/sub/PublicSubclass.java
deleted file mode 100644
index 2ccd42a..0000000
--- a/javatests/dagger/functional/sub/PublicSubclass.java
+++ /dev/null
@@ -1,26 +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.functional.sub;
-
-import dagger.functional.Generic;
-import javax.inject.Inject;
-
-public class PublicSubclass extends Generic<PackagePrivate> {
- @Inject public PublicSubclass(PackagePrivate pp) {
- super(pp);
- }
-}
diff --git a/javatests/dagger/functional/sub/PublicSubclass2.java b/javatests/dagger/functional/sub/PublicSubclass2.java
deleted file mode 100644
index 3d5f429..0000000
--- a/javatests/dagger/functional/sub/PublicSubclass2.java
+++ /dev/null
@@ -1,26 +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.functional.sub;
-
-import dagger.functional.Generic;
-import javax.inject.Inject;
-
-public class PublicSubclass2 extends Generic<PackagePrivateContainer.PublicEnclosed> {
- @Inject public PublicSubclass2(PackagePrivateContainer.PublicEnclosed pp) {
- super(pp);
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/AnInterface.java b/javatests/dagger/functional/subcomponent/AnInterface.java
deleted file mode 100644
index f0d9b4c..0000000
--- a/javatests/dagger/functional/subcomponent/AnInterface.java
+++ /dev/null
@@ -1,20 +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.functional.subcomponent;
-
-interface AnInterface {
-}
diff --git a/javatests/dagger/functional/subcomponent/BoundAsSingleton.java b/javatests/dagger/functional/subcomponent/BoundAsSingleton.java
deleted file mode 100644
index 9d14465..0000000
--- a/javatests/dagger/functional/subcomponent/BoundAsSingleton.java
+++ /dev/null
@@ -1,28 +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.functional.subcomponent;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-@Documented
-@Retention(RUNTIME)
-@Qualifier
-@interface BoundAsSingleton {}
diff --git a/javatests/dagger/functional/subcomponent/ChildAbstractClassComponent.java b/javatests/dagger/functional/subcomponent/ChildAbstractClassComponent.java
deleted file mode 100644
index b9bcce2..0000000
--- a/javatests/dagger/functional/subcomponent/ChildAbstractClassComponent.java
+++ /dev/null
@@ -1,23 +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.functional.subcomponent;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = {ChildModule.class, StaticChildModule.class})
-abstract class ChildAbstractClassComponent implements ChildComponent {
-}
diff --git a/javatests/dagger/functional/subcomponent/ChildComponent.java b/javatests/dagger/functional/subcomponent/ChildComponent.java
deleted file mode 100644
index 6d6fd8b..0000000
--- a/javatests/dagger/functional/subcomponent/ChildComponent.java
+++ /dev/null
@@ -1,34 +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.functional.subcomponent;
-
-import dagger.Subcomponent;
-import java.util.Set;
-import javax.inject.Provider;
-
-@Subcomponent(modules = {ChildModule.class, StaticChildModule.class})
-interface ChildComponent {
- Provider<UnscopedType> getUnscopedTypeProvider();
-
- RequiresSingletons requiresSingleton();
-
- Set<Object> objectSet();
-
- GrandchildComponent newGrandchildComponent();
-
- Object object();
-}
diff --git a/javatests/dagger/functional/subcomponent/ChildComponentRequiringModules.java b/javatests/dagger/functional/subcomponent/ChildComponentRequiringModules.java
deleted file mode 100644
index 29b60e2..0000000
--- a/javatests/dagger/functional/subcomponent/ChildComponentRequiringModules.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = {
- ChildModule.class,
- ChildModuleWithParameters.class,
- ChildModuleWithState.class})
-interface ChildComponentRequiringModules {
- int getInt();
-}
diff --git a/javatests/dagger/functional/subcomponent/ChildModule.java b/javatests/dagger/functional/subcomponent/ChildModule.java
deleted file mode 100644
index f11cefc..0000000
--- a/javatests/dagger/functional/subcomponent/ChildModule.java
+++ /dev/null
@@ -1,34 +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.functional.subcomponent;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class ChildModule {
- @Provides
- @IntoSet
- static Object provideUnscopedObject() {
- return new Object() {
- @Override public String toString() {
- return "unscoped in child";
- }
- };
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/ChildModuleWithParameters.java b/javatests/dagger/functional/subcomponent/ChildModuleWithParameters.java
deleted file mode 100644
index 17f8471..0000000
--- a/javatests/dagger/functional/subcomponent/ChildModuleWithParameters.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent;
-
-import dagger.Module;
-
-/**
- * This is a module that can't be constructed with a default constructor.
- */
-@Module
-final class ChildModuleWithParameters {
- public ChildModuleWithParameters(@SuppressWarnings("unused") Object whatever) {}
-}
diff --git a/javatests/dagger/functional/subcomponent/ChildModuleWithState.java b/javatests/dagger/functional/subcomponent/ChildModuleWithState.java
deleted file mode 100644
index 49b266c..0000000
--- a/javatests/dagger/functional/subcomponent/ChildModuleWithState.java
+++ /dev/null
@@ -1,33 +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.functional.subcomponent;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * This is a module that can be constructed with a default constructor, but has state, so callers
- * might want to pass a reference anyway.
- */
-@Module
-final class ChildModuleWithState {
- private int i = 0;
-
- @Provides int provideInt() {
- return i++;
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/GenericParentComponent.java b/javatests/dagger/functional/subcomponent/GenericParentComponent.java
deleted file mode 100644
index f49083b..0000000
--- a/javatests/dagger/functional/subcomponent/GenericParentComponent.java
+++ /dev/null
@@ -1,21 +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.functional.subcomponent;
-
-interface GenericParentComponent<B> {
- B subcomponent();
-}
diff --git a/javatests/dagger/functional/subcomponent/GrandchildComponent.java b/javatests/dagger/functional/subcomponent/GrandchildComponent.java
deleted file mode 100644
index 5a1b772..0000000
--- a/javatests/dagger/functional/subcomponent/GrandchildComponent.java
+++ /dev/null
@@ -1,32 +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.functional.subcomponent;
-
-import dagger.Subcomponent;
-import java.util.Set;
-import javax.inject.Provider;
-
-@Subcomponent(modules = GrandchildModule.class)
-interface GrandchildComponent {
- Provider<UnscopedType> getUnscopedTypeProvider();
-
- RequiresSingletons requiresSingleton();
-
- Set<Object> objectSet();
-
- NeedsAnInterface needsAnInterface();
-}
diff --git a/javatests/dagger/functional/subcomponent/GrandchildModule.java b/javatests/dagger/functional/subcomponent/GrandchildModule.java
deleted file mode 100644
index c61accf..0000000
--- a/javatests/dagger/functional/subcomponent/GrandchildModule.java
+++ /dev/null
@@ -1,43 +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.functional.subcomponent;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-abstract class GrandchildModule {
- @Provides
- @IntoSet
- static Object provideUnscopedObject() {
- return new Object() {
- @Override public String toString() {
- return "unscoped in grandchild";
- }
- };
- }
-
- @Binds
- abstract AnInterface provideAnInterface(ImplementsAnInterface implementsAnInterface);
-
- @Provides
- static NeedsAnInterface provideNeedsAnInterface(AnInterface anInterface) {
- return new NeedsAnInterface(anInterface);
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/ImplementsAnInterface.java b/javatests/dagger/functional/subcomponent/ImplementsAnInterface.java
deleted file mode 100644
index a07025c..0000000
--- a/javatests/dagger/functional/subcomponent/ImplementsAnInterface.java
+++ /dev/null
@@ -1,24 +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.functional.subcomponent;
-
-import javax.inject.Inject;
-
-class ImplementsAnInterface implements AnInterface {
- @Inject ImplementsAnInterface() {}
-}
-
diff --git a/javatests/dagger/functional/subcomponent/ModuleWithSubcomponentsTest.java b/javatests/dagger/functional/subcomponent/ModuleWithSubcomponentsTest.java
deleted file mode 100644
index 06beae1..0000000
--- a/javatests/dagger/functional/subcomponent/ModuleWithSubcomponentsTest.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.functional.subcomponent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Module;
-import dagger.functional.subcomponent.UsesModuleSubcomponents.ParentIncludesSubcomponentTransitively;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link Module#subcomponents()}. */
-@RunWith(JUnit4.class)
-public class ModuleWithSubcomponentsTest {
-
- @Test
- public void subcomponentFromModules() {
- UsesModuleSubcomponents parent = DaggerUsesModuleSubcomponents.create();
- assertThat(parent.strings()).containsExactly("from parent");
- assertThat(parent.usesChild().strings).containsExactly("from parent", "from child");
- }
-
- @Test
- public void subcomponentFromModules_transitively() {
- ParentIncludesSubcomponentTransitively parent =
- DaggerUsesModuleSubcomponents_ParentIncludesSubcomponentTransitively.create();
- assertThat(parent.strings()).containsExactly("from parent");
- assertThat(parent.usesChild().strings).containsExactly("from parent", "from child");
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/MultibindingSubcomponents.java b/javatests/dagger/functional/subcomponent/MultibindingSubcomponents.java
deleted file mode 100644
index 9959771..0000000
--- a/javatests/dagger/functional/subcomponent/MultibindingSubcomponents.java
+++ /dev/null
@@ -1,254 +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.functional.subcomponent;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import dagger.multibindings.StringKey;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import javax.inject.Inject;
-
-final class MultibindingSubcomponents {
-
- /** Multibindings for this type are bound only in the parent component. */
- enum BoundInParent {
- INSTANCE;
- }
-
- /** Multibindings for this type are bound only in the child component. */
- enum BoundInChild {
- INSTANCE;
- }
-
- /** Multibindings for this type are bound in the parent component and the child component. */
- enum BoundInParentAndChild {
- IN_PARENT,
- IN_CHILD;
- }
-
- static final class RequiresMultibindings<T> {
- private final Set<T> set;
- private final Map<String, T> map;
-
- @Inject
- RequiresMultibindings(Set<T> set, Map<String, T> map) {
- this.set = set;
- this.map = map;
- }
-
- Set<T> set() {
- return set;
- }
-
- Map<String, T> map() {
- return map;
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof RequiresMultibindings<?>
- && set.equals(((RequiresMultibindings<?>) obj).set)
- && map.equals(((RequiresMultibindings<?>) obj).map);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(set, map);
- }
-
- @Override
- public String toString() {
- return String.format(
- "%s{set=%s, map=%s}", RequiresMultibindings.class.getSimpleName(), set, map);
- }
- }
-
- @Module
- abstract static class ParentMultibindingModule {
-
- @Provides
- @IntoSet
- static BoundInParent onlyInParentElement() {
- return BoundInParent.INSTANCE;
- }
-
- @Provides
- @IntoMap
- @StringKey("parent key")
- static BoundInParent onlyInParentEntry() {
- return BoundInParent.INSTANCE;
- }
-
- @Provides
- @IntoSet
- static BoundInParentAndChild inParentAndChildElement() {
- return BoundInParentAndChild.IN_PARENT;
- }
-
- @Provides
- @IntoMap
- @StringKey("parent key")
- static BoundInParentAndChild inParentAndChildEntry() {
- return BoundInParentAndChild.IN_PARENT;
- }
-
- /* This is not static because otherwise we have no tests that cover the case where a
- * subcomponent uses a module instance installed onto a parent component. */
- @Binds
- @IntoSet
- abstract RequiresMultibindings<BoundInParentAndChild>
- requiresMultibindingsInParentAndChildElement(
- RequiresMultibindings<BoundInParentAndChild> requiresMultibindingsInParentAndChild);
- }
-
- @Module
- static final class ChildMultibindingModule {
-
- @Provides
- @IntoSet
- static BoundInParentAndChild inParentAndChildElement() {
- return BoundInParentAndChild.IN_CHILD;
- }
-
- @Provides
- @IntoMap
- @StringKey("child key")
- static BoundInParentAndChild inParentAndChildEntry() {
- return BoundInParentAndChild.IN_CHILD;
- }
-
- @Provides
- @IntoSet
- static BoundInChild onlyInChildElement() {
- return BoundInChild.INSTANCE;
- }
-
- @Provides
- @IntoMap
- @StringKey("child key")
- static BoundInChild onlyInChildEntry() {
- return BoundInChild.INSTANCE;
- }
- }
-
- @Module
- abstract static class ChildMultibindingModuleWithOnlyBindsMultibindings {
- @Provides
- static BoundInParentAndChild provideBoundInParentAndChildForBinds() {
- return BoundInParentAndChild.IN_CHILD;
- }
-
- @Binds
- @IntoSet
- abstract BoundInParentAndChild bindsLocalContribution(BoundInParentAndChild instance);
-
- @Binds
- @IntoMap
- @StringKey("child key")
- abstract BoundInParentAndChild inParentAndChildEntry(BoundInParentAndChild instance);
-
- @Provides
- static BoundInChild provideBoundInChildForBinds() {
- return BoundInChild.INSTANCE;
- }
-
- @Binds
- @IntoSet
- abstract BoundInChild inChild(BoundInChild instance);
-
- @Binds
- @IntoMap
- @StringKey("child key")
- abstract BoundInChild inChildEntry(BoundInChild instance);
- }
-
- interface ProvidesBoundInParent {
- RequiresMultibindings<BoundInParent> requiresMultibindingsBoundInParent();
- }
-
- interface ProvidesBoundInChild {
- RequiresMultibindings<BoundInChild> requiresMultibindingsBoundInChild();
- }
-
- interface ProvidesBoundInParentAndChild {
- RequiresMultibindings<BoundInParentAndChild> requiresMultibindingsBoundInParentAndChild();
- }
-
- interface ProvidesSetOfRequiresMultibindings {
- Set<RequiresMultibindings<BoundInParentAndChild>> setOfRequiresMultibindingsInParentAndChild();
- }
-
- interface ParentWithProvision
- extends ProvidesBoundInParent, ProvidesBoundInParentAndChild,
- ProvidesSetOfRequiresMultibindings {}
-
- interface HasChildWithProvision {
- ChildWithProvision childWithProvision();
- }
-
- interface HasChildWithoutProvision {
- ChildWithoutProvision childWithoutProvision();
- }
-
- @Component(modules = ParentMultibindingModule.class)
- interface ParentWithoutProvisionHasChildWithoutProvision extends HasChildWithoutProvision {}
-
- @Component(modules = ParentMultibindingModule.class)
- interface ParentWithoutProvisionHasChildWithProvision extends HasChildWithProvision {}
-
- @Component(modules = ParentMultibindingModule.class)
- interface ParentWithProvisionHasChildWithoutProvision
- extends ParentWithProvision, HasChildWithoutProvision {}
-
- @Component(modules = ParentMultibindingModule.class)
- interface ParentWithProvisionHasChildWithProvision
- extends ParentWithProvision, HasChildWithProvision {}
-
- @Subcomponent(modules = ChildMultibindingModule.class)
- interface ChildWithoutProvision {
- Grandchild grandchild();
- }
-
- @Subcomponent(modules = ChildMultibindingModule.class)
- interface ChildWithProvision
- extends ProvidesBoundInParent, ProvidesBoundInParentAndChild, ProvidesBoundInChild,
- ProvidesSetOfRequiresMultibindings {
-
- Grandchild grandchild();
- }
-
- @Subcomponent
- interface Grandchild
- extends ProvidesBoundInParent, ProvidesBoundInParentAndChild, ProvidesBoundInChild,
- ProvidesSetOfRequiresMultibindings {}
-
- @Component(modules = ParentMultibindingModule.class)
- interface ParentWithProvisionHasChildWithBinds extends ParentWithProvision {
- ChildWithBinds childWithBinds();
- }
-
- @Subcomponent(modules = ChildMultibindingModuleWithOnlyBindsMultibindings.class)
- interface ChildWithBinds extends ChildWithProvision {}
-
-}
diff --git a/javatests/dagger/functional/subcomponent/NeedsAnInterface.java b/javatests/dagger/functional/subcomponent/NeedsAnInterface.java
deleted file mode 100644
index 3efbad7..0000000
--- a/javatests/dagger/functional/subcomponent/NeedsAnInterface.java
+++ /dev/null
@@ -1,21 +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.functional.subcomponent;
-
-class NeedsAnInterface {
- NeedsAnInterface(@SuppressWarnings("unused") AnInterface anInterface) {}
-}
diff --git a/javatests/dagger/functional/subcomponent/ParentComponent.java b/javatests/dagger/functional/subcomponent/ParentComponent.java
deleted file mode 100644
index 4c0b608..0000000
--- a/javatests/dagger/functional/subcomponent/ParentComponent.java
+++ /dev/null
@@ -1,39 +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.functional.subcomponent;
-
-import dagger.Component;
-import dagger.functional.SomeQualifier;
-import javax.inject.Singleton;
-
-@Component(modules = {ParentModule.class, UnresolvableChildComponentModule.class})
-@Singleton
-interface ParentComponent extends ParentGetters {
- ChildComponent newChildComponent();
-
- ChildAbstractClassComponent newChildAbstractClassComponent();
-
- ChildComponentRequiringModules newChildComponentRequiringModules(
- ChildModuleWithParameters cmwp,
- ChildModuleWithState childModuleWithState);
-
- /**
- * Requests a qualified version of this subcomponent builder, which does not install it as a
- * subcomponent, but instead, uses the explicit binding of this qualified builder.
- */
- @SomeQualifier UnresolvableChildComponent.Builder unresolvableChildComponentBuilder();
-}
diff --git a/javatests/dagger/functional/subcomponent/ParentGetters.java b/javatests/dagger/functional/subcomponent/ParentGetters.java
deleted file mode 100644
index 928bff2..0000000
--- a/javatests/dagger/functional/subcomponent/ParentGetters.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent;
-
-import java.util.Set;
-import javax.inject.Provider;
-
-interface ParentGetters {
- Provider<UnscopedType> getUnscopedTypeProvider();
-
- Set<Object> objectSet();
-
-}
diff --git a/javatests/dagger/functional/subcomponent/ParentModule.java b/javatests/dagger/functional/subcomponent/ParentModule.java
deleted file mode 100644
index 8ce4b87..0000000
--- a/javatests/dagger/functional/subcomponent/ParentModule.java
+++ /dev/null
@@ -1,52 +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.functional.subcomponent;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-import javax.inject.Singleton;
-
-@Module
-abstract class ParentModule {
- @Provides
- @IntoSet
- static Object provideUnscopedObject() {
- return new Object() {
- @Override public String toString() {
- return "unscoped in parent";
- }
- };
- }
-
- @Provides
- @IntoSet
- @Singleton
- static Object provideSingletonObject() {
- return new Object() {
- @Override public String toString() {
- return "singleton";
- }
- };
- }
-
- @Binds
- @Singleton
- @BoundAsSingleton
- abstract UnscopedType provideUnscopedTypeBoundAsSingleton(UnscopedType unscopedType);
-}
diff --git a/javatests/dagger/functional/subcomponent/ParentOfGenericComponent.java b/javatests/dagger/functional/subcomponent/ParentOfGenericComponent.java
deleted file mode 100644
index cc701f4..0000000
--- a/javatests/dagger/functional/subcomponent/ParentOfGenericComponent.java
+++ /dev/null
@@ -1,25 +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.functional.subcomponent;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-@Component(modules = ParentModule.class)
-@Singleton
-interface ParentOfGenericComponent extends GenericParentComponent<ChildComponent>, ParentGetters {
-}
diff --git a/javatests/dagger/functional/subcomponent/RequiresSingletons.java b/javatests/dagger/functional/subcomponent/RequiresSingletons.java
deleted file mode 100644
index 8dc9b3d..0000000
--- a/javatests/dagger/functional/subcomponent/RequiresSingletons.java
+++ /dev/null
@@ -1,38 +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.functional.subcomponent;
-
-import javax.inject.Inject;
-
-final class RequiresSingletons {
- private final SingletonType singletonType;
- private final UnscopedType unscopedTypeBoundAsSingleton;
-
- @Inject RequiresSingletons(SingletonType singletonType,
- @BoundAsSingleton UnscopedType unscopedTypeBoundAsSingleton) {
- this.singletonType = singletonType;
- this.unscopedTypeBoundAsSingleton = unscopedTypeBoundAsSingleton;
- }
-
- SingletonType singletonType() {
- return singletonType;
- }
-
- UnscopedType unscopedTypeBoundAsSingleton() {
- return unscopedTypeBoundAsSingleton;
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/SingletonType.java b/javatests/dagger/functional/subcomponent/SingletonType.java
deleted file mode 100644
index 9a6da6c..0000000
--- a/javatests/dagger/functional/subcomponent/SingletonType.java
+++ /dev/null
@@ -1,25 +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.functional.subcomponent;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton
-final class SingletonType {
- @Inject SingletonType() {}
-}
diff --git a/javatests/dagger/functional/subcomponent/StaticChildModule.java b/javatests/dagger/functional/subcomponent/StaticChildModule.java
deleted file mode 100644
index fcd0cd5..0000000
--- a/javatests/dagger/functional/subcomponent/StaticChildModule.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.functional.subcomponent;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class StaticChildModule {
- private StaticChildModule() {}
-
- @Provides static Object provideStaticObject() {
- return "static";
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/SubcomponentFactoryMethodTest.java b/javatests/dagger/functional/subcomponent/SubcomponentFactoryMethodTest.java
deleted file mode 100644
index ca811af..0000000
--- a/javatests/dagger/functional/subcomponent/SubcomponentFactoryMethodTest.java
+++ /dev/null
@@ -1,74 +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.functional.subcomponent;
-
-import static org.junit.Assert.fail;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for subcomponent factory methods. */
-@RunWith(JUnit4.class)
-public final class SubcomponentFactoryMethodTest {
-
- @Module
- static class IntModule {
- @Provides
- int provideInt() {
- return 42;
- }
- }
-
- @Module
- static class StringModule {
- final String s;
-
- StringModule(String s) {
- this.s = s;
- }
-
- @Provides
- String provideString(int i) {
- return s + i;
- }
- }
-
- @Component(modules = IntModule.class)
- interface TestComponent {
- TestSubcomponent newSubcomponent(StringModule stringModule);
- }
-
- @Subcomponent(modules = StringModule.class)
- interface TestSubcomponent {
- String string();
- }
-
- @Test
- public void creatingSubcomponentViaFactoryMethod_failsForNullParameter() {
- TestComponent component = DaggerSubcomponentFactoryMethodTest_TestComponent.create();
- try {
- component.newSubcomponent(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/SubcomponentFromModuleAndFactoryMethod.java b/javatests/dagger/functional/subcomponent/SubcomponentFromModuleAndFactoryMethod.java
deleted file mode 100644
index b8b8806..0000000
--- a/javatests/dagger/functional/subcomponent/SubcomponentFromModuleAndFactoryMethod.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.functional.subcomponent;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-
-/**
- * Tests for {@link Subcomponent}s which are defined with {@link Module#subcomponents()} and are
- * also requested as component factory methods.
- */
-public class SubcomponentFromModuleAndFactoryMethod {
- @Subcomponent
- interface Sub {
- @Subcomponent.Builder
- interface Builder {
- Sub sub();
- }
- }
-
- @Module(subcomponents = Sub.class)
- class ModuleWithSubcomponent {}
-
- @Component(modules = ModuleWithSubcomponent.class)
- interface ExposesBuilder {
- Sub.Builder subcomponentBuilder();
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/SubcomponentMultibindingsTest.java b/javatests/dagger/functional/subcomponent/SubcomponentMultibindingsTest.java
deleted file mode 100644
index eeadbeb..0000000
--- a/javatests/dagger/functional/subcomponent/SubcomponentMultibindingsTest.java
+++ /dev/null
@@ -1,282 +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.functional.subcomponent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.functional.subcomponent.MultibindingSubcomponents.BoundInChild;
-import dagger.functional.subcomponent.MultibindingSubcomponents.BoundInParent;
-import dagger.functional.subcomponent.MultibindingSubcomponents.BoundInParentAndChild;
-import dagger.functional.subcomponent.MultibindingSubcomponents.ParentWithProvisionHasChildWithProvision;
-import dagger.functional.subcomponent.MultibindingSubcomponents.ParentWithProvisionHasChildWithoutProvision;
-import dagger.functional.subcomponent.MultibindingSubcomponents.ParentWithoutProvisionHasChildWithProvision;
-import dagger.functional.subcomponent.MultibindingSubcomponents.ParentWithoutProvisionHasChildWithoutProvision;
-import dagger.functional.subcomponent.MultibindingSubcomponents.RequiresMultibindings;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SubcomponentMultibindingsTest {
-
- private static final RequiresMultibindings<BoundInParent> BOUND_IN_PARENT =
- new RequiresMultibindings<>(
- ImmutableSet.of(BoundInParent.INSTANCE),
- ImmutableMap.of("parent key", BoundInParent.INSTANCE));
-
- private static final RequiresMultibindings<BoundInChild> BOUND_IN_CHILD =
- new RequiresMultibindings<>(
- ImmutableSet.of(BoundInChild.INSTANCE),
- ImmutableMap.of("child key", BoundInChild.INSTANCE));
-
- private static final RequiresMultibindings<BoundInParentAndChild> BOUND_IN_PARENT_AND_CHILD =
- new RequiresMultibindings<>(
- ImmutableSet.of(BoundInParentAndChild.IN_PARENT, BoundInParentAndChild.IN_CHILD),
- ImmutableMap.of(
- "parent key", BoundInParentAndChild.IN_PARENT,
- "child key", BoundInParentAndChild.IN_CHILD));
-
- private static final RequiresMultibindings<BoundInParentAndChild>
- BOUND_IN_PARENT_AND_CHILD_PROVIDED_BY_PARENT =
- new RequiresMultibindings<>(
- ImmutableSet.of(BoundInParentAndChild.IN_PARENT),
- ImmutableMap.of("parent key", BoundInParentAndChild.IN_PARENT));
-
- private ParentWithoutProvisionHasChildWithoutProvision
- parentWithoutProvisionHasChildWithoutProvision;
- private ParentWithoutProvisionHasChildWithProvision parentWithoutProvisionHasChildWithProvision;
- private ParentWithProvisionHasChildWithoutProvision parentWithProvisionHasChildWithoutProvision;
- private ParentWithProvisionHasChildWithProvision parentWithProvisionHasChildWithProvision;
-
- @Before
- public void setUp() {
- parentWithoutProvisionHasChildWithoutProvision =
- DaggerMultibindingSubcomponents_ParentWithoutProvisionHasChildWithoutProvision.create();
- parentWithoutProvisionHasChildWithProvision =
- DaggerMultibindingSubcomponents_ParentWithoutProvisionHasChildWithProvision.create();
- parentWithProvisionHasChildWithoutProvision =
- DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithoutProvision.create();
- parentWithProvisionHasChildWithProvision =
- DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithProvision.create();
- }
-
- @Test
- public void testParentWithoutProvisionHasChildWithoutProvision() {
- // Child
- assertThat(
- parentWithoutProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
-
- // Grandchild
- assertThat(
- parentWithoutProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
- assertThat(
- parentWithoutProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInChild())
- .isEqualTo(BOUND_IN_CHILD);
-
- /*
- * Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
- * contribution from the child, it must be pushed down to (not duplicated in) the child because
- * its contribution depends on multibindings that have one contribution from the parent and one
- * from the child.
- *
- */
- assertThat(
- parentWithoutProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .setOfRequiresMultibindingsInParentAndChild())
- .containsExactly(BOUND_IN_PARENT_AND_CHILD);
- }
-
- @Test
- public void testParentWithoutProvisionHasChildWithProvision() {
- // Child
- assertThat(
- parentWithoutProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
-
- // Grandchild
- assertThat(
- parentWithoutProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
- assertThat(
- parentWithoutProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInChild())
- .isEqualTo(BOUND_IN_CHILD);
-
- /*
- * Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
- * contribution from the child, it must be pushed down to (not duplicated in) the child because
- * its contribution depends on multibindings that have one contribution from the parent and one
- * from the child.
- *
- */
- assertThat(
- parentWithoutProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .setOfRequiresMultibindingsInParentAndChild())
- .containsExactly(BOUND_IN_PARENT_AND_CHILD);
- }
-
- @Test
- public void testParentWithProvisionHasChildWithoutProvision() {
- // Parent
- assertThat(parentWithProvisionHasChildWithoutProvision.requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
-
- assertThat(
- parentWithProvisionHasChildWithoutProvision
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD_PROVIDED_BY_PARENT);
-
- // Grandchild
- assertThat(
- parentWithProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
- assertThat(
- parentWithProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInChild())
- .isEqualTo(BOUND_IN_CHILD);
-
- assertThat(
- parentWithProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
-
- /*
- * Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
- * contribution from the child, it must be pushed down to (not duplicated in) the child because
- * its contribution depends on multibindings that have one contribution from the parent and one
- * from the child.
- *
- */
- assertThat(
- parentWithProvisionHasChildWithoutProvision
- .childWithoutProvision()
- .grandchild()
- .setOfRequiresMultibindingsInParentAndChild())
- .containsExactly(BOUND_IN_PARENT_AND_CHILD);
- }
-
- @Test
- public void testParentWithProvisionHasChildWithProvision() {
- // Parent
- assertThat(parentWithProvisionHasChildWithProvision.requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
-
- // Child
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .requiresMultibindingsBoundInChild())
- .isEqualTo(BOUND_IN_CHILD);
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
-
- // https://github.com/google/dagger/issues/401
- assertThat(
- DaggerMultibindingSubcomponents_ParentWithProvisionHasChildWithBinds.create()
- .childWithBinds()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
-
- /*
- * Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
- * contribution from the child, it must be pushed down to (not duplicated in) the child because
- * its contribution depends on multibindings that have one contribution from the parent and one
- * from the child.
- *
- */
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .setOfRequiresMultibindingsInParentAndChild())
- .containsExactly(BOUND_IN_PARENT_AND_CHILD);
-
- // Grandchild
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInParent())
- .isEqualTo(BOUND_IN_PARENT);
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInChild())
- .isEqualTo(BOUND_IN_CHILD);
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .requiresMultibindingsBoundInParentAndChild())
- .isEqualTo(BOUND_IN_PARENT_AND_CHILD);
-
- /*
- * Even though the multibinding for Set<RequiresMultiboundObjects> does not itself have a
- * contribution from the child, it must be pushed down to (not duplicated in) the child because
- * its contribution depends on multibindings that have one contribution from the parent and one
- * from the child.
- *
- */
- assertThat(
- parentWithProvisionHasChildWithProvision
- .childWithProvision()
- .grandchild()
- .setOfRequiresMultibindingsInParentAndChild())
- .containsExactly(BOUND_IN_PARENT_AND_CHILD);
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/SubcomponentTest.java b/javatests/dagger/functional/subcomponent/SubcomponentTest.java
deleted file mode 100644
index c34de0a..0000000
--- a/javatests/dagger/functional/subcomponent/SubcomponentTest.java
+++ /dev/null
@@ -1,122 +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.functional.subcomponent;
-
-import static com.google.common.collect.Sets.intersection;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.TruthJUnit.assume;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Set;
-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 SubcomponentTest {
- private static final ParentComponent parentComponent = DaggerParentComponent.create();
- private static final ParentOfGenericComponent parentOfGenericComponent =
- DaggerParentOfGenericComponent.create();
-
- @Parameters
- public static Collection<Object[]> parameters() {
- return Arrays.asList(new Object[][] {
- { parentComponent, parentComponent.newChildComponent() },
- { parentComponent, parentComponent.newChildAbstractClassComponent() },
- { parentOfGenericComponent, parentOfGenericComponent.subcomponent() }});
- }
-
- private final ParentGetters parentGetters;
- private final ChildComponent childComponent;
-
- public SubcomponentTest(ParentGetters parentGetters, ChildComponent childComponent) {
- this.parentGetters = parentGetters;
- this.childComponent = childComponent;
- }
-
- @Test
- public void scopePropagatesUpward_class() {
- assertThat(childComponent.requiresSingleton().singletonType())
- .isSameInstanceAs(childComponent.requiresSingleton().singletonType());
- assertThat(childComponent.requiresSingleton().singletonType())
- .isSameInstanceAs(
- childComponent.newGrandchildComponent().requiresSingleton().singletonType());
- }
-
- @Test
- public void scopePropagatesUpward_provides() {
- assertThat(childComponent.requiresSingleton().unscopedTypeBoundAsSingleton())
- .isSameInstanceAs(childComponent.requiresSingleton().unscopedTypeBoundAsSingleton());
- assertThat(childComponent.requiresSingleton().unscopedTypeBoundAsSingleton())
- .isSameInstanceAs(
- childComponent
- .newGrandchildComponent()
- .requiresSingleton()
- .unscopedTypeBoundAsSingleton());
- }
-
- @Test
- public void multibindingContributions() {
- Set<Object> parentObjectSet = parentGetters.objectSet();
- assertThat(parentObjectSet).hasSize(2);
- Set<Object> childObjectSet = childComponent.objectSet();
- assertThat(childObjectSet).hasSize(3);
- Set<Object> grandchildObjectSet =
- childComponent.newGrandchildComponent().objectSet();
- assertThat(grandchildObjectSet).hasSize(4);
- assertThat(intersection(parentObjectSet, childObjectSet)).hasSize(1);
- assertThat(intersection(parentObjectSet, grandchildObjectSet)).hasSize(1);
- assertThat(intersection(childObjectSet, grandchildObjectSet)).hasSize(1);
- }
-
- @Test
- public void unscopedProviders() {
- assume().that(System.getProperty("dagger.mode")).doesNotContain("FastInit");
- assertThat(parentGetters.getUnscopedTypeProvider())
- .isSameInstanceAs(childComponent.getUnscopedTypeProvider());
- assertThat(parentGetters.getUnscopedTypeProvider())
- .isSameInstanceAs(childComponent.newGrandchildComponent().getUnscopedTypeProvider());
- }
-
- @Test
- public void passedModules() {
- ChildModuleWithState childModuleWithState = new ChildModuleWithState();
- ChildComponentRequiringModules childComponent1 =
- parentComponent.newChildComponentRequiringModules(
- new ChildModuleWithParameters(new Object()),
- childModuleWithState);
- ChildComponentRequiringModules childComponent2 =
- parentComponent.newChildComponentRequiringModules(
- new ChildModuleWithParameters(new Object()),
- childModuleWithState);
- assertThat(childComponent1.getInt()).isEqualTo(0);
- assertThat(childComponent2.getInt()).isEqualTo(1);
- }
-
- @Test
- public void dependenceisInASubcomponent() {
- assertThat(childComponent.newGrandchildComponent().needsAnInterface()).isNotNull();
- }
-
- @Test
- public void qualifiedSubcomponentIsBound() {
- assertThat(parentComponent.unresolvableChildComponentBuilder().build().unboundString())
- .isEqualTo("unbound");
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/Unbound.java b/javatests/dagger/functional/subcomponent/Unbound.java
deleted file mode 100644
index ae80621..0000000
--- a/javatests/dagger/functional/subcomponent/Unbound.java
+++ /dev/null
@@ -1,32 +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.functional.subcomponent;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * A qualifier representing an unbound type, to verify that the compiler does not attempt to
- * generate code depending on it.
- */
-@Documented
-@Retention(RUNTIME)
-@Qualifier
-@interface Unbound {}
diff --git a/javatests/dagger/functional/subcomponent/UnresolvableChildComponent.java b/javatests/dagger/functional/subcomponent/UnresolvableChildComponent.java
deleted file mode 100644
index 57d9d0d..0000000
--- a/javatests/dagger/functional/subcomponent/UnresolvableChildComponent.java
+++ /dev/null
@@ -1,39 +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.functional.subcomponent;
-
-import dagger.Subcomponent;
-
-/**
- * A subcomponent that's not resolvable in any parent component, for testing that qualified methods
- * on components that return subcomponents do not trigger actual subcomponents.
- */
-@Subcomponent
-interface UnresolvableChildComponent {
- /**
- * Requests a type that is never bound in any component that this subcomponent might be installed
- * in. If this subcomponent is ever attempted to be installed in a component, then it will produce
- * a compiler error.
- */
- @Unbound
- String unboundString();
-
- @Subcomponent.Builder
- interface Builder {
- UnresolvableChildComponent build();
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/UnresolvableChildComponentModule.java b/javatests/dagger/functional/subcomponent/UnresolvableChildComponentModule.java
deleted file mode 100644
index 613e7e3..0000000
--- a/javatests/dagger/functional/subcomponent/UnresolvableChildComponentModule.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.functional.subcomponent;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.functional.SomeQualifier;
-
-@Module
-final class UnresolvableChildComponentModule {
- /**
- * Provides a qualified version of the {@link UnresolvableChildComponent}'s builder. If the
- * subcomponent were actually installed in a component, this would be a duplicate binding; but
- * since that doesn't happen, this binding is OK.
- */
- @Provides
- @SomeQualifier
- static UnresolvableChildComponent.Builder unresolvableChildComponentBuilder() {
- return new UnresolvableChildComponent.Builder() {
- @Override
- public UnresolvableChildComponent build() {
- return new UnresolvableChildComponent() {
- @Override
- public String unboundString() {
- return "unbound";
- }
- };
- }
- };
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/UnscopedType.java b/javatests/dagger/functional/subcomponent/UnscopedType.java
deleted file mode 100644
index c167457..0000000
--- a/javatests/dagger/functional/subcomponent/UnscopedType.java
+++ /dev/null
@@ -1,23 +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.functional.subcomponent;
-
-import javax.inject.Inject;
-
-final class UnscopedType {
- @Inject UnscopedType(@SuppressWarnings("unused") SingletonType singletonType) {}
-}
diff --git a/javatests/dagger/functional/subcomponent/UsesModuleSubcomponents.java b/javatests/dagger/functional/subcomponent/UsesModuleSubcomponents.java
deleted file mode 100644
index bd240af..0000000
--- a/javatests/dagger/functional/subcomponent/UsesModuleSubcomponents.java
+++ /dev/null
@@ -1,80 +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.functional.subcomponent;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.multibindings.IntoSet;
-import java.util.Set;
-import javax.inject.Inject;
-
-/** Supporting types for {@link ModuleWithSubcomponentsTest}. */
-@Component(modules = UsesModuleSubcomponents.ModuleWithSubcomponents.class)
-public interface UsesModuleSubcomponents {
- UsesChild usesChild();
-
- Set<String> strings();
-
- @Module(subcomponents = Child.class, includes = AlsoIncludesSubcomponents.class)
- class ModuleWithSubcomponents {
- @Provides
- @IntoSet
- static String provideStringInParent() {
- return "from parent";
- }
- }
-
- @Module(subcomponents = Child.class)
- class AlsoIncludesSubcomponents {}
-
- @Subcomponent(modules = ChildModule.class)
- interface Child {
- Set<String> strings();
-
- @Subcomponent.Builder
- interface Builder {
- Child build();
- }
- }
-
- @Module
- class ChildModule {
- @Provides
- @IntoSet
- static String provideStringInChild() {
- return "from child";
- }
- }
-
- class UsesChild {
- Set<String> strings;
-
- @Inject
- UsesChild(Child.Builder childBuilder) {
- this.strings = childBuilder.build().strings();
- }
- }
-
- @Module(includes = ModuleWithSubcomponents.class)
- class OnlyIncludesModuleWithSubcomponents {}
-
- @Component(modules = OnlyIncludesModuleWithSubcomponents.class)
- interface ParentIncludesSubcomponentTransitively extends UsesModuleSubcomponents {}
-
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java b/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java
deleted file mode 100644
index 7cb4fce..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent.hiding;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = dagger.functional.subcomponent.hiding.b.CommonModuleName.class)
-interface ChildComponent {
- //ensure that t.s.h.a.CommonName gets bound in this component
- dagger.functional.subcomponent.hiding.a.CommonName aCommonName();
- //ensure that t.s.h.b.CommonName gets bound in this component
- dagger.functional.subcomponent.hiding.b.CommonName bCommonName();
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/ParentComponent.java b/javatests/dagger/functional/subcomponent/hiding/ParentComponent.java
deleted file mode 100644
index 7458d82..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/ParentComponent.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.functional.subcomponent.hiding;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-@Component(modules = dagger.functional.subcomponent.hiding.a.CommonModuleName.class)
-@Singleton
-interface ParentComponent {
- // ensure that t.s.h.a.CommonName gets bound in this component
- dagger.functional.subcomponent.hiding.a.CommonName aCommonName();
-
- ChildComponent newChildComponent();
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/SubcomponentHidingTest.java b/javatests/dagger/functional/subcomponent/hiding/SubcomponentHidingTest.java
deleted file mode 100644
index 398b8a7..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/SubcomponentHidingTest.java
+++ /dev/null
@@ -1,33 +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.functional.subcomponent.hiding;
-
-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 SubcomponentHidingTest {
- @Test public void moduleNameHiding() {
- ParentComponent parent = DaggerParentComponent.create();
- assertThat(parent.aCommonName().toString()).isEqualTo("a");
- assertThat(parent.newChildComponent().aCommonName().toString()).isEqualTo("a");
- assertThat(parent.newChildComponent().bCommonName().toString()).isEqualTo("1");
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/a/CommonModuleName.java b/javatests/dagger/functional/subcomponent/hiding/a/CommonModuleName.java
deleted file mode 100644
index d13446c..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/a/CommonModuleName.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent.hiding.a;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public class CommonModuleName {
- @Provides String provideString() {
- return "a";
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/a/CommonName.java b/javatests/dagger/functional/subcomponent/hiding/a/CommonName.java
deleted file mode 100644
index 567fc39..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/a/CommonName.java
+++ /dev/null
@@ -1,32 +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.functional.subcomponent.hiding.a;
-
-import javax.inject.Inject;
-
-public final class CommonName {
- private final String s;
-
- @Inject CommonName(String s) {
- this.s = s;
- }
-
- @Override
- public String toString() {
- return s;
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/b/CommonModuleName.java b/javatests/dagger/functional/subcomponent/hiding/b/CommonModuleName.java
deleted file mode 100644
index b05356f..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/b/CommonModuleName.java
+++ /dev/null
@@ -1,27 +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.functional.subcomponent.hiding.b;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public class CommonModuleName {
- @Provides int provideString() {
- return 1;
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/hiding/b/CommonName.java b/javatests/dagger/functional/subcomponent/hiding/b/CommonName.java
deleted file mode 100644
index 1136f64..0000000
--- a/javatests/dagger/functional/subcomponent/hiding/b/CommonName.java
+++ /dev/null
@@ -1,32 +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.functional.subcomponent.hiding.b;
-
-import javax.inject.Inject;
-
-public final class CommonName {
- private final int i;
-
- @Inject CommonName(int i) {
- this.i = i;
- }
-
- @Override
- public String toString() {
- return Integer.toString(i);
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/pruning/ParentDoesntUseSubcomponent.java b/javatests/dagger/functional/subcomponent/pruning/ParentDoesntUseSubcomponent.java
deleted file mode 100644
index 516a52c..0000000
--- a/javatests/dagger/functional/subcomponent/pruning/ParentDoesntUseSubcomponent.java
+++ /dev/null
@@ -1,95 +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.functional.subcomponent.pruning;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.multibindings.IntoSet;
-import java.util.Set;
-import javax.inject.Qualifier;
-
-/**
- * Supporting types for {@link SubcomponentOnlyRequestedBySiblingTest}. {@link ChildA} is a direct
- * child of the top level component, but is only requested within its sibling, not directly from its
- * parent.
- */
-@Component(modules = ParentDoesntUseSubcomponent.ParentModule.class)
-interface ParentDoesntUseSubcomponent {
-
- ChildB.Builder childBBuilder();
-
- @Subcomponent(modules = ChildAModule.class)
- interface ChildA {
- @Subcomponent.Builder
- interface Builder {
- ChildA build();
- }
-
- Set<Class<?>> componentHierarchy();
- }
-
- @Subcomponent(modules = ChildBModule.class)
- interface ChildB {
- @Subcomponent.Builder
- interface Builder {
- ChildB build();
- }
-
- Set<Class<?>> componentHierarchy();
-
- @FromChildA
- Set<Class<?>> componentHierarchyFromChildA();
- }
-
- @Module(subcomponents = {ChildA.class, ChildB.class})
- class ParentModule {
- @Provides
- @IntoSet
- static Class<?> provideComponentType() {
- return ParentDoesntUseSubcomponent.class;
- }
- }
-
- @Module
- class ChildAModule {
- @Provides
- @IntoSet
- static Class<?> provideComponentType() {
- return ChildA.class;
- }
- }
-
- @Module
- class ChildBModule {
- @Provides
- @IntoSet
- static Class<?> provideComponentType() {
- return ChildB.class;
- }
-
- @Provides
- @FromChildA
- Set<Class<?>> fromChildA(ChildA.Builder childABuilder) {
- return childABuilder.build().componentHierarchy();
- }
- }
-
- @Qualifier
- @interface FromChildA {}
-}
diff --git a/javatests/dagger/functional/subcomponent/pruning/SubcomponentOnlyRequestedBySiblingTest.java b/javatests/dagger/functional/subcomponent/pruning/SubcomponentOnlyRequestedBySiblingTest.java
deleted file mode 100644
index 40a784a..0000000
--- a/javatests/dagger/functional/subcomponent/pruning/SubcomponentOnlyRequestedBySiblingTest.java
+++ /dev/null
@@ -1,49 +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.functional.subcomponent.pruning;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.functional.subcomponent.pruning.ParentDoesntUseSubcomponent.ChildA;
-import dagger.functional.subcomponent.pruning.ParentDoesntUseSubcomponent.ChildB;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for {@link Subcomponent}s which are included with {@link Module#subcomponents()} but not
- * used directly within the component which adds them.
- *
- * <p>This tests to make sure that while resolving one subcomponent (A), another subcomponent (B)
- * can be requested if they have a shared ancestor component. If that shared ancestor did not
- * resolve B directly via any of its entry points, B will still be generated since it is requested
- * by a descendant.
- */
-@RunWith(JUnit4.class)
-public class SubcomponentOnlyRequestedBySiblingTest {
- @Test
- public void subcomponentAddedInParent_onlyUsedInSibling() {
- ParentDoesntUseSubcomponent parent = DaggerParentDoesntUseSubcomponent.create();
- ChildB childB = parent.childBBuilder().build();
- assertThat(childB.componentHierarchy())
- .containsExactly(ParentDoesntUseSubcomponent.class, ChildB.class);
- assertThat(childB.componentHierarchyFromChildA())
- .containsExactly(ParentDoesntUseSubcomponent.class, ChildA.class);
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInChild.java b/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInChild.java
deleted file mode 100644
index b3318cf..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInChild.java
+++ /dev/null
@@ -1,21 +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.functional.subcomponent.repeat;
-
-abstract class OnlyUsedInChild {
-
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInParent.java b/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInParent.java
deleted file mode 100644
index 1e8d4cd..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/OnlyUsedInParent.java
+++ /dev/null
@@ -1,21 +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.functional.subcomponent.repeat;
-
-abstract class OnlyUsedInParent {
-
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/OtherSubcomponentWithRepeatedModule.java b/javatests/dagger/functional/subcomponent/repeat/OtherSubcomponentWithRepeatedModule.java
deleted file mode 100644
index 82cd021..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/OtherSubcomponentWithRepeatedModule.java
+++ /dev/null
@@ -1,30 +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.functional.subcomponent.repeat;
-
-import dagger.Subcomponent;
-
-@Subcomponent(modules = RepeatedModule.class)
-interface OtherSubcomponentWithRepeatedModule extends SubcomponentWithRepeatedModule {
-
- @Subcomponent.Builder
- interface Builder {
- Builder repeatedModule(RepeatedModule repeatedModule);
-
- OtherSubcomponentWithRepeatedModule build();
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/ParentComponent.java b/javatests/dagger/functional/subcomponent/repeat/ParentComponent.java
deleted file mode 100644
index 1578596..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/ParentComponent.java
+++ /dev/null
@@ -1,40 +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.functional.subcomponent.repeat;
-
-import dagger.Component;
-import java.util.Set;
-
-@Component(modules = RepeatedModule.class)
-interface ParentComponent {
- Object state();
-
- String getString();
- Set<String> getMultiboundStrings();
- OnlyUsedInParent getOnlyUsedInParent();
-
- SubcomponentWithRepeatedModule.Builder newChildComponentBuilder();
-
- SubcomponentWithoutRepeatedModule newChildComponentWithoutRepeatedModule();
-
- @Component.Builder
- interface Builder {
- Builder repeatedModule(RepeatedModule repeatedModule);
-
- ParentComponent build();
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/RepeatedModule.java b/javatests/dagger/functional/subcomponent/repeat/RepeatedModule.java
deleted file mode 100644
index 55d7de9..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/RepeatedModule.java
+++ /dev/null
@@ -1,52 +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.functional.subcomponent.repeat;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-
-@Module
-final class RepeatedModule {
- private final Object state = new Object();
-
- @Provides
- Object state() {
- return state;
- }
-
- @Provides
- static String provideString() {
- return "a string";
- }
-
- @Provides
- @IntoSet
- static String contributeString() {
- return "a string in a set";
- }
-
- @Provides
- static OnlyUsedInParent provideOnlyUsedInParent() {
- return new OnlyUsedInParent() {};
- }
-
- @Provides
- static OnlyUsedInChild provideOnlyUsedInChild() {
- return new OnlyUsedInChild() {};
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/RepeatedModuleTest.java b/javatests/dagger/functional/subcomponent/repeat/RepeatedModuleTest.java
deleted file mode 100644
index 9bf3a39..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/RepeatedModuleTest.java
+++ /dev/null
@@ -1,85 +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.functional.subcomponent.repeat;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class RepeatedModuleTest {
- private ParentComponent parentComponent;
-
- @Before
- public void initializeParentComponent() {
- this.parentComponent = DaggerParentComponent.builder().build();
- }
-
- @Test
- public void repeatedModuleHasSameStateInSubcomponent() {
- SubcomponentWithRepeatedModule childComponent =
- parentComponent.newChildComponentBuilder().build();
- assertThat(parentComponent.state()).isSameInstanceAs(childComponent.state());
- }
-
- @Test
- public void repeatedModuleHasSameStateInGrandchildSubcomponent() {
- SubcomponentWithoutRepeatedModule childComponent =
- parentComponent.newChildComponentWithoutRepeatedModule();
- SubcomponentWithRepeatedModule grandchildComponent =
- childComponent.newGrandchildBuilder().build();
- assertThat(parentComponent.state()).isSameInstanceAs(grandchildComponent.state());
- }
-
- @Test
- public void repeatedModuleBuilderThrowsInSubcomponent() {
- SubcomponentWithRepeatedModule.Builder childComponentBuilder =
- parentComponent.newChildComponentBuilder();
- try {
- childComponentBuilder.repeatedModule(new RepeatedModule());
- fail();
- } catch (UnsupportedOperationException expected) {
- assertThat(expected)
- .hasMessageThat()
- .isEqualTo(
- "dagger.functional.subcomponent.repeat.RepeatedModule cannot be set "
- + "because it is inherited from the enclosing component");
- }
- }
-
- @Test
- public void repeatedModuleBuilderThrowsInGrandchildSubcomponent() {
- SubcomponentWithoutRepeatedModule childComponent =
- parentComponent.newChildComponentWithoutRepeatedModule();
- OtherSubcomponentWithRepeatedModule.Builder grandchildComponentBuilder =
- childComponent.newGrandchildBuilder();
- try {
- grandchildComponentBuilder.repeatedModule(new RepeatedModule());
- fail();
- } catch (UnsupportedOperationException expected) {
- assertThat(expected)
- .hasMessageThat()
- .isEqualTo(
- "dagger.functional.subcomponent.repeat.RepeatedModule cannot be set "
- + "because it is inherited from the enclosing component");
- }
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithRepeatedModule.java b/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithRepeatedModule.java
deleted file mode 100644
index 0762374..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithRepeatedModule.java
+++ /dev/null
@@ -1,38 +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.functional.subcomponent.repeat;
-
-import dagger.Subcomponent;
-import java.util.Set;
-
-@Subcomponent(modules = RepeatedModule.class)
-interface SubcomponentWithRepeatedModule {
- Object state();
-
- String getString();
-
- Set<String> getMultiboundStrings();
-
- OnlyUsedInChild getOnlyUsedInChild();
-
- @Subcomponent.Builder
- interface Builder {
- Builder repeatedModule(RepeatedModule repeatedModule);
-
- SubcomponentWithRepeatedModule build();
- }
-}
diff --git a/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java b/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
deleted file mode 100644
index 5930f51..0000000
--- a/javatests/dagger/functional/subcomponent/repeat/SubcomponentWithoutRepeatedModule.java
+++ /dev/null
@@ -1,24 +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.functional.subcomponent.repeat;
-
-import dagger.Subcomponent;
-
-@Subcomponent
-interface SubcomponentWithoutRepeatedModule {
- OtherSubcomponentWithRepeatedModule.Builder newGrandchildBuilder();
-}
diff --git a/javatests/dagger/functional/tck/BUILD b/javatests/dagger/functional/tck/BUILD
deleted file mode 100644
index 7526bf0..0000000
--- a/javatests/dagger/functional/tck/BUILD
+++ /dev/null
@@ -1,42 +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:
-# TCK tests for Dagger
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-load("//:test_defs.bzl", "GenJavaTests")
-
-GenJavaTests(
- name = "tck_tests",
- srcs = glob(["*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- lib_javacopts = [
- "-Adagger.privateMemberValidation=warning",
- "-Adagger.staticMemberValidation=warning",
- "-Adagger.ignorePrivateAndStaticInjectionForComponent=enabled",
- ],
- deps = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@google_bazel_common//third_party/java/jsr330_inject:tck",
- "@google_bazel_common//third_party/java/junit",
- ],
-)
diff --git a/javatests/dagger/functional/tck/CarModule.java b/javatests/dagger/functional/tck/CarModule.java
deleted file mode 100644
index 3c44d60..0000000
--- a/javatests/dagger/functional/tck/CarModule.java
+++ /dev/null
@@ -1,28 +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.functional.tck;
-
-import dagger.Binds;
-import dagger.Module;
-import org.atinject.tck.auto.Car;
-import org.atinject.tck.auto.Convertible;
-
-@Module
-abstract class CarModule {
- @Binds
- abstract Car provideConvertible(Convertible convertible);
-}
diff --git a/javatests/dagger/functional/tck/CarShop.java b/javatests/dagger/functional/tck/CarShop.java
deleted file mode 100644
index d9e64d6..0000000
--- a/javatests/dagger/functional/tck/CarShop.java
+++ /dev/null
@@ -1,36 +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.functional.tck;
-
-import dagger.Component;
-import javax.inject.Singleton;
-import org.atinject.tck.auto.Car;
-
-@Singleton
-@Component(
- modules = {
- CarModule.class,
- TireModule.class,
- SeatModule.class,
- EngineModule.class,
- FuelTankModule.class
- }
-)
-public interface CarShop {
- @SuppressWarnings("dependency-cycle")
- Car make();
-}
diff --git a/javatests/dagger/functional/tck/EngineModule.java b/javatests/dagger/functional/tck/EngineModule.java
deleted file mode 100644
index 331b064..0000000
--- a/javatests/dagger/functional/tck/EngineModule.java
+++ /dev/null
@@ -1,35 +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.functional.tck;
-
-import dagger.MembersInjector;
-import dagger.Module;
-import dagger.Provides;
-import org.atinject.tck.auto.Engine;
-import org.atinject.tck.auto.V8Engine;
-
-@Module
-public class EngineModule {
- @Provides
- static Engine provideEngine(MembersInjector<V8Engine> injector) {
- // This is provided because V8Engine has no @Inject constructor and Dagger requires an @Inject
- // constructor, however this is a TCK supplied class that we prefer to leave unmodified.
- V8Engine engine = new V8Engine();
- injector.injectMembers(engine);
- return engine;
- }
-}
diff --git a/javatests/dagger/functional/tck/FuelTankModule.java b/javatests/dagger/functional/tck/FuelTankModule.java
deleted file mode 100644
index b5f2800..0000000
--- a/javatests/dagger/functional/tck/FuelTankModule.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.functional.tck;
-
-import dagger.Module;
-import dagger.Provides;
-import org.atinject.tck.auto.FuelTank;
-
-@Module
-class FuelTankModule {
- @Provides
- static FuelTank provideFuelTank() {
- return new FuelTank();
- }
-}
diff --git a/javatests/dagger/functional/tck/SeatModule.java b/javatests/dagger/functional/tck/SeatModule.java
deleted file mode 100644
index c3574ea..0000000
--- a/javatests/dagger/functional/tck/SeatModule.java
+++ /dev/null
@@ -1,30 +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.functional.tck;
-
-import dagger.Binds;
-import dagger.Module;
-import org.atinject.tck.auto.Drivers;
-import org.atinject.tck.auto.DriversSeat;
-import org.atinject.tck.auto.Seat;
-
-@Module
-abstract class SeatModule {
- @Binds
- @Drivers
- abstract Seat provideSeat(DriversSeat seat);
-}
diff --git a/javatests/dagger/functional/tck/TckTest.java b/javatests/dagger/functional/tck/TckTest.java
deleted file mode 100644
index a49972d..0000000
--- a/javatests/dagger/functional/tck/TckTest.java
+++ /dev/null
@@ -1,34 +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.functional.tck;
-
-import junit.framework.Test;
-import org.atinject.tck.Tck;
-import org.atinject.tck.auto.Car;
-import org.atinject.tck.auto.Convertible;
-
-/**
- * Test suite to execute the JSR-330 TCK in JUnit.
- */
-public class TckTest {
- public static Test suite() {
- CarShop carShopComponent = DaggerCarShop.create();
- Car car = carShopComponent.make();
- Convertible.localConvertible.set((Convertible) car);
- return Tck.testsFor(car, false, false);
- }
-}
diff --git a/javatests/dagger/functional/tck/TireModule.java b/javatests/dagger/functional/tck/TireModule.java
deleted file mode 100644
index e6b6d58..0000000
--- a/javatests/dagger/functional/tck/TireModule.java
+++ /dev/null
@@ -1,30 +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.functional.tck;
-
-import dagger.Binds;
-import dagger.Module;
-import javax.inject.Named;
-import org.atinject.tck.auto.Tire;
-import org.atinject.tck.auto.accessories.SpareTire;
-
-@Module
-abstract class TireModule {
- @Binds
- @Named("spare")
- abstract Tire provideTire(SpareTire sparetire);
-}
diff --git a/javatests/dagger/grpc/functional/server/BUILD b/javatests/dagger/grpc/functional/server/BUILD
deleted file mode 100644
index 1e8c2e6..0000000
--- a/javatests/dagger/grpc/functional/server/BUILD
+++ /dev/null
@@ -1,19 +0,0 @@
-# Functional tests for Dagger-gRPC
-
-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
-
-java_proto_library(
- name = "coffee_service_java_proto",
- deps = [":protos"],
-)
-
-proto_library(
- name = "protos",
- srcs = glob(["*.proto"]),
-)
diff --git a/javatests/dagger/grpc/functional/server/BaristaTest.java b/javatests/dagger/grpc/functional/server/BaristaTest.java
deleted file mode 100644
index d6c5b42..0000000
--- a/javatests/dagger/grpc/functional/server/BaristaTest.java
+++ /dev/null
@@ -1,154 +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.grpc.functional.server;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.util.concurrent.Futures.getUnchecked;
-import static com.google.protos.test.CoffeeService.CoffeeType.AMERICANO;
-import static com.google.protos.test.CoffeeService.CoffeeType.DRIP;
-import static com.google.protos.test.CoffeeService.CoffeeType.ESPRESSO;
-import static com.google.protos.test.CoffeeService.CoffeeType.LATTE;
-import static com.google.protos.test.CoffeeService.CoffeeType.POUR_OVER;
-import static java.util.Arrays.asList;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.SettableFuture;
-import com.google.protos.test.BaristaGrpc;
-import com.google.protos.test.BaristaGrpc.BaristaStub;
-import com.google.protos.test.CoffeeService.CoffeeRequest;
-import com.google.protos.test.CoffeeService.CoffeeResponse;
-import com.google.protos.test.CoffeeService.CoffeeType;
-import io.grpc.inprocess.InProcessChannelBuilder;
-import io.grpc.stub.StreamObserver;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-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 BaristaTest {
-
- private static final class CoffeeResponseObserver implements StreamObserver<CoffeeResponse> {
- private final SettableFuture<Void> completion = SettableFuture.create();
- private final List<CoffeeResponse> responses = new ArrayList<>();
-
- List<CoffeeResponse> responses() {
- getUnchecked(completion);
- return responses;
- }
-
- @Override
- public void onNext(CoffeeResponse value) {
- responses.add(value);
- }
-
- @Override
- public void onError(Throwable t) {
- completion.setException(t);
- }
-
- @Override
- public void onCompleted() {
- completion.set(null);
- }
- }
-
- @ClassRule
- public static CoffeeServerResource coffeeServerWithCallScope =
- new CoffeeServerResource("CallScope", DaggerCoffeeServerWithCallScopeService.builder());
-
- @ClassRule
- public static CoffeeServerResource coffeeServerWithSingletonScope =
- new CoffeeServerResource("Unscoped", DaggerCoffeeServerWithUnscopedService.builder());
-
- @Parameters(name = "{0}")
- public static Iterable<Object[]> coffeeServers() {
- return ImmutableList.copyOf(
- new Object[][] {{coffeeServerWithCallScope}, {coffeeServerWithSingletonScope}});
- }
-
- @Rule public final VerifyInterceptor verifyCount;
- private final CoffeeServerResource coffeeServer;
- private final CoffeeResponseObserver responseObserver = new CoffeeResponseObserver();
-
- private BaristaStub barista;
-
- public BaristaTest(CoffeeServerResource coffeeServer) {
- this.coffeeServer = coffeeServer;
- this.verifyCount = new VerifyInterceptor(coffeeServer);
- }
-
- @Before
- public void setUp() {
- barista = BaristaGrpc.newStub(InProcessChannelBuilder.forName(coffeeServer.name()).build());
- }
-
- @Test
- public void testUnaryGetCoffee() {
- barista.unaryGetCoffee(request(POUR_OVER, LATTE), responseObserver);
- assertThat(responseObserver.responses())
- .containsExactly(response("Here you go!", POUR_OVER, LATTE));
- }
-
- @Test
- public void testClientStreamingGetCoffee() {
- StreamObserver<CoffeeRequest> requestObserver =
- barista.clientStreamingGetCoffee(responseObserver);
- requestObserver.onNext(request(POUR_OVER, LATTE));
- requestObserver.onNext(request(AMERICANO));
- requestObserver.onNext(request(DRIP, ESPRESSO));
- requestObserver.onCompleted();
- assertThat(responseObserver.responses())
- .containsExactly(response("All yours!", POUR_OVER, LATTE, AMERICANO, DRIP, ESPRESSO));
- }
-
- @Test
- public void testServerStreamingGetCoffee() {
- barista.serverStreamingGetCoffee(request(DRIP, AMERICANO), responseObserver);
- assertThat(responseObserver.responses())
- .containsExactly(
- response("Here's a DRIP", DRIP), response("Here's a AMERICANO", AMERICANO));
- }
-
- @Test
- public void testBidiStreamingGetCoffee() {
- StreamObserver<CoffeeRequest> requestObserver =
- barista.bidiStreamingGetCoffee(responseObserver);
- requestObserver.onNext(request(POUR_OVER, LATTE));
- requestObserver.onNext(request(AMERICANO));
- requestObserver.onNext(request(DRIP, ESPRESSO));
- requestObserver.onCompleted();
- assertThat(responseObserver.responses())
- .containsExactly(
- response("Enjoy!", POUR_OVER, LATTE),
- response("Enjoy!", AMERICANO),
- response("Enjoy!", DRIP, ESPRESSO));
- }
-
- private CoffeeRequest request(CoffeeType... types) {
- return CoffeeRequest.newBuilder().addAllType(asList(types)).build();
- }
-
- private CoffeeResponse response(String message, CoffeeType... types) {
- return CoffeeResponse.newBuilder().setMessage(message).addAllCup(asList(types)).build();
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/CoffeeServer.java b/javatests/dagger/grpc/functional/server/CoffeeServer.java
deleted file mode 100644
index 10a0fd2..0000000
--- a/javatests/dagger/grpc/functional/server/CoffeeServer.java
+++ /dev/null
@@ -1,41 +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.grpc.functional.server;
-
-import dagger.grpc.server.InProcessServerModule;
-import io.grpc.Server;
-import java.io.IOException;
-
-abstract class CoffeeServer<T extends CoffeeServer<T>> {
- protected abstract Server server();
-
- public void start() throws IOException {
- server().start();
- }
-
- public void shutdown() {
- server().shutdownNow();
- }
-
- abstract CountingInterceptor countingInterceptor();
-
- interface Builder<T extends CoffeeServer<T>> {
- Builder<T> inProcessServerModule(InProcessServerModule serverModule);
-
- T build();
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/CoffeeServerResource.java b/javatests/dagger/grpc/functional/server/CoffeeServerResource.java
deleted file mode 100644
index dc449fb..0000000
--- a/javatests/dagger/grpc/functional/server/CoffeeServerResource.java
+++ /dev/null
@@ -1,55 +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.grpc.functional.server;
-
-import dagger.grpc.server.InProcessServerModule;
-import java.io.IOException;
-import org.junit.rules.ExternalResource;
-
-final class CoffeeServerResource extends ExternalResource {
- private final String name;
- private final CoffeeServer<?> coffeeServer;
-
- CoffeeServerResource(String name, CoffeeServer.Builder<?> coffeeServerBuilder) {
- this.name = name;
- this.coffeeServer =
- coffeeServerBuilder.inProcessServerModule(InProcessServerModule.serverNamed(name)).build();
- }
-
- public String name() {
- return name;
- }
-
- public int methodCount(String methodName) {
- return coffeeServer.countingInterceptor().countCalls(methodName);
- }
-
- @Override
- protected void before() throws IOException, InterruptedException {
- coffeeServer.start();
- }
-
- @Override
- protected void after() {
- coffeeServer.shutdown();
- }
-
- @Override
- public String toString() {
- return name;
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/CoffeeServerWithCallScopeService.java b/javatests/dagger/grpc/functional/server/CoffeeServerWithCallScopeService.java
deleted file mode 100644
index 5fb06b6..0000000
--- a/javatests/dagger/grpc/functional/server/CoffeeServerWithCallScopeService.java
+++ /dev/null
@@ -1,64 +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.grpc.functional.server;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-import dagger.grpc.functional.server.CoffeeServerWithCallScopeService.CallScopeServiceModule;
-import dagger.grpc.functional.server.CountingInterceptor.CountingInterceptorModule;
-import dagger.grpc.server.CallScoped;
-import dagger.grpc.server.GrpcCallMetadataModule;
-import dagger.grpc.server.InProcessServerModule;
-import javax.inject.Singleton;
-
-@Singleton
-@Component(modules = {InProcessServerModule.class, CallScopeServiceModule.class})
-abstract class CoffeeServerWithCallScopeService
- extends CoffeeServer<CoffeeServerWithCallScopeService> {
-
- @Component.Builder
- interface Builder extends CoffeeServer.Builder<CoffeeServerWithCallScopeService> {}
-
- abstract BaristaCallScope baristaCallScope(GrpcCallMetadataModule callMetadataModule);
-
- @CallScoped
- @Subcomponent(
- modules = {
- GrpcCallMetadataModule.class,
- FriendlyBaristaGrpcServiceModule.class,
- CountingInterceptorModule.class
- }
- )
- interface BaristaCallScope extends FriendlyBaristaServiceDefinition {}
-
- @Module(includes = FriendlyBaristaGrpcProxyModule.class)
- static class CallScopeServiceModule {
- @Provides
- static FriendlyBaristaServiceDefinition.Factory friendlyBaristaServiceDefinitionFactory(
- final CoffeeServerWithCallScopeService testServer) {
- return new FriendlyBaristaServiceDefinition.Factory() {
- @Override
- public FriendlyBaristaServiceDefinition grpcService(
- GrpcCallMetadataModule grpcCallMetadataModule) {
- return testServer.baristaCallScope(grpcCallMetadataModule);
- }
- };
- }
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/CoffeeServerWithUnscopedService.java b/javatests/dagger/grpc/functional/server/CoffeeServerWithUnscopedService.java
deleted file mode 100644
index 3346f84..0000000
--- a/javatests/dagger/grpc/functional/server/CoffeeServerWithUnscopedService.java
+++ /dev/null
@@ -1,47 +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.grpc.functional.server;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.grpc.functional.server.CoffeeServerWithUnscopedService.UnscopedServiceModule;
-import dagger.grpc.functional.server.CountingInterceptor.CountingInterceptorModule;
-import dagger.grpc.server.InProcessServerModule;
-import javax.inject.Singleton;
-
-@Singleton
-@Component(
- modules = {
- InProcessServerModule.class,
- UnscopedServiceModule.class,
- CountingInterceptorModule.class
- }
-)
-abstract class CoffeeServerWithUnscopedService extends CoffeeServer<CoffeeServerWithUnscopedService>
- implements FriendlyBaristaServiceDefinition {
-
- @Component.Builder
- interface Builder extends CoffeeServer.Builder<CoffeeServerWithUnscopedService> {}
-
- @Module(includes = FriendlyBaristaUnscopedGrpcServiceModule.class)
- abstract static class UnscopedServiceModule {
- @Binds
- abstract FriendlyBaristaServiceDefinition friendlyBaristaServiceDefinition(
- CoffeeServerWithUnscopedService testServer);
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/CountingInterceptor.java b/javatests/dagger/grpc/functional/server/CountingInterceptor.java
deleted file mode 100644
index 4d53782..0000000
--- a/javatests/dagger/grpc/functional/server/CountingInterceptor.java
+++ /dev/null
@@ -1,65 +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.grpc.functional.server;
-
-import static java.util.Arrays.asList;
-
-import com.google.common.collect.ConcurrentHashMultiset;
-import com.google.common.collect.Multiset;
-import com.google.protos.test.BaristaGrpc;
-import dagger.Module;
-import dagger.Provides;
-import dagger.grpc.server.ForGrpcService;
-import io.grpc.Metadata;
-import io.grpc.ServerCall;
-import io.grpc.ServerCall.Listener;
-import io.grpc.ServerCallHandler;
-import io.grpc.ServerInterceptor;
-import java.util.List;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton
-class CountingInterceptor implements ServerInterceptor {
- private final Multiset<String> calls = ConcurrentHashMultiset.create();
-
- @Inject
- CountingInterceptor() {}
-
- @Override
- public <RequestT, ResponseT> Listener<RequestT> interceptCall(
- ServerCall<RequestT, ResponseT> call,
- Metadata headers,
- ServerCallHandler<RequestT, ResponseT> next) {
- calls.add(call.getMethodDescriptor().getFullMethodName());
- return next.startCall(call, headers);
- }
-
- public int countCalls(String methodName) {
- return calls.count(methodName);
- }
-
- @Module
- static class CountingInterceptorModule {
- @Provides
- @ForGrpcService(BaristaGrpc.class)
- static List<? extends ServerInterceptor> testServiceInterceptors(
- CountingInterceptor countingInterceptor) {
- return asList(countingInterceptor);
- }
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/FriendlyBarista.java b/javatests/dagger/grpc/functional/server/FriendlyBarista.java
deleted file mode 100644
index 2c0246f..0000000
--- a/javatests/dagger/grpc/functional/server/FriendlyBarista.java
+++ /dev/null
@@ -1,106 +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.grpc.functional.server;
-
-import static java.util.Collections.singletonList;
-
-import com.google.protos.test.BaristaGrpc;
-import com.google.protos.test.BaristaGrpc.BaristaImplBase;
-import com.google.protos.test.CoffeeService.CoffeeRequest;
-import com.google.protos.test.CoffeeService.CoffeeResponse;
-import com.google.protos.test.CoffeeService.CoffeeType;
-import dagger.grpc.server.GrpcService;
-import io.grpc.stub.StreamObserver;
-import java.util.List;
-import javax.inject.Inject;
-
-@GrpcService(grpcClass = BaristaGrpc.class)
-class FriendlyBarista extends BaristaImplBase {
-
- @Inject
- FriendlyBarista() {}
-
- @Override
- public void unaryGetCoffee(
- CoffeeRequest request, StreamObserver<CoffeeResponse> responseObserver) {
- responseObserver.onNext(response("Here you go!", request.getTypeList()));
- responseObserver.onCompleted();
- }
-
- @Override
- public StreamObserver<CoffeeRequest> clientStreamingGetCoffee(
- final StreamObserver<CoffeeResponse> responseObserver) {
- return new StreamObserver<CoffeeRequest>() {
-
- private final CoffeeResponse.Builder response = CoffeeResponse.newBuilder();
-
- @Override
- public void onNext(CoffeeRequest value) {
- response.addAllCup(value.getTypeList());
- }
-
- @Override
- public void onError(Throwable t) {}
-
- @Override
- public void onCompleted() {
- response.setMessage("All yours!");
- responseObserver.onNext(response.build());
- responseObserver.onCompleted();
- }
- };
- }
-
- @Override
- public void serverStreamingGetCoffee(
- CoffeeRequest request, StreamObserver<CoffeeResponse> responseObserver) {
- for (CoffeeType type : request.getTypeList()) {
- responseObserver.onNext(response("Here's a " + type, singletonList(type)));
- }
- responseObserver.onCompleted();
- }
-
- @Override
- public StreamObserver<CoffeeRequest> bidiStreamingGetCoffee(
- final StreamObserver<CoffeeResponse> responseObserver) {
- return new StreamObserver<CoffeeRequest>() {
-
- private int responses;
-
- @Override
- public void onNext(CoffeeRequest value) {
- responseObserver.onNext(response("Enjoy!", value.getTypeList()));
- if (responses++ > 10) {
- responseObserver.onNext(CoffeeResponse.newBuilder().setMessage("We're done.").build());
- responseObserver.onCompleted();
- }
- }
-
- @Override
- public void onError(Throwable t) {}
-
- @Override
- public void onCompleted() {
- responseObserver.onCompleted();
- }
- };
- }
-
- private CoffeeResponse response(String message, List<CoffeeType> types) {
- return CoffeeResponse.newBuilder().addAllCup(types).setMessage(message).build();
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/VerifyInterceptor.java b/javatests/dagger/grpc/functional/server/VerifyInterceptor.java
deleted file mode 100644
index 99ecedb..0000000
--- a/javatests/dagger/grpc/functional/server/VerifyInterceptor.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.grpc.functional.server;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.protos.test.BaristaGrpc;
-import io.grpc.MethodDescriptor;
-import java.lang.annotation.Retention;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-final class VerifyInterceptor implements TestRule {
-
- @Retention(RUNTIME)
- @interface MethodName {
- String value();
- }
-
- private final CoffeeServerResource coffeeServer;
-
- VerifyInterceptor(CoffeeServerResource coffeeServer) {
- this.coffeeServer = coffeeServer;
- }
-
- @Override
- public Statement apply(final Statement base, Description description) {
- MethodName annotation = description.getAnnotation(MethodName.class);
- if (annotation == null) {
- return base;
- }
- final String fullMethodName =
- MethodDescriptor.generateFullMethodName(BaristaGrpc.SERVICE_NAME, annotation.value());
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- int calls = coffeeServer.methodCount(fullMethodName);
- base.evaluate();
- assertWithMessage("Calls to %s", fullMethodName)
- .that(coffeeServer.methodCount(fullMethodName))
- .isEqualTo(calls + 1);
- }
- };
- }
-}
diff --git a/javatests/dagger/grpc/functional/server/coffee_service.proto b/javatests/dagger/grpc/functional/server/coffee_service.proto
deleted file mode 100644
index a14c794..0000000
--- a/javatests/dagger/grpc/functional/server/coffee_service.proto
+++ /dev/null
@@ -1,50 +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.
-
-syntax = "proto3";
-
-package test;
-
-enum CoffeeType {
- UNKNOWN = 0;
- DRIP = 1;
- POUR_OVER = 2;
- ESPRESSO = 3;
- AMERICANO = 4;
- LATTE = 5;
-}
-
-message CoffeeRequest {
- repeated CoffeeType type = 1;
-}
-
-message CoffeeResponse {
- repeated CoffeeType cup = 1;
- string message = 2;
-}
-
-service Barista {
- rpc UnaryGetCoffee(CoffeeRequest) returns (CoffeeResponse) {
- }
-
- rpc ClientStreamingGetCoffee(stream CoffeeRequest) returns (CoffeeResponse) {
- }
-
- rpc ServerStreamingGetCoffee(CoffeeRequest) returns (stream CoffeeResponse) {
- }
-
- rpc BidiStreamingGetCoffee(stream CoffeeRequest)
- returns (stream CoffeeResponse) {
- }
-}
diff --git a/javatests/dagger/internal/DoubleCheckTest.java b/javatests/dagger/internal/DoubleCheckTest.java
deleted file mode 100644
index e36c1bc..0000000
--- a/javatests/dagger/internal/DoubleCheckTest.java
+++ /dev/null
@@ -1,170 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Uninterruptibles;
-import dagger.Lazy;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DoubleCheckTest {
- @Test
- public void provider_nullPointerException() {
- try {
- DoubleCheck.provider(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Test
- public void lazy_nullPointerException() {
- try {
- DoubleCheck.lazy(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- private static final Provider<Object> DOUBLE_CHECK_OBJECT_PROVIDER =
- DoubleCheck.provider(Object::new);
-
- @Test
- public void doubleWrapping_provider() {
- assertThat(DoubleCheck.provider(DOUBLE_CHECK_OBJECT_PROVIDER))
- .isSameInstanceAs(DOUBLE_CHECK_OBJECT_PROVIDER);
- }
-
- @Test
- public void doubleWrapping_lazy() {
- assertThat(DoubleCheck.lazy(DOUBLE_CHECK_OBJECT_PROVIDER))
- .isSameInstanceAs(DOUBLE_CHECK_OBJECT_PROVIDER);
- }
-
- @Test
- public void get() throws Exception {
- int numThreads = 10;
- ExecutorService executor = Executors.newFixedThreadPool(numThreads);
-
- final CountDownLatch latch = new CountDownLatch(numThreads);
- LatchedProvider provider = new LatchedProvider(latch);
- final Lazy<Object> lazy = DoubleCheck.lazy(provider);
-
- List<Callable<Object>> tasks = Lists.newArrayListWithCapacity(numThreads);
- for (int i = 0; i < numThreads; i++) {
- tasks.add(
- () -> {
- latch.countDown();
- return lazy.get();
- });
- }
-
- List<Future<Object>> futures = executor.invokeAll(tasks);
-
- assertThat(provider.provisions.get()).isEqualTo(1);
- Set<Object> results = Sets.newIdentityHashSet();
- for (Future<Object> future : futures) {
- results.add(future.get());
- }
- assertThat(results).hasSize(1);
- }
-
- private static class LatchedProvider implements Provider<Object> {
- final AtomicInteger provisions;
- final CountDownLatch latch;
-
- LatchedProvider(CountDownLatch latch) {
- this.latch = latch;
- this.provisions = new AtomicInteger();
- }
-
- @Override
- public Object get() {
- if (latch != null) {
- Uninterruptibles.awaitUninterruptibly(latch);
- }
- provisions.incrementAndGet();
- return new Object();
- }
- }
-
- @Test public void reentranceWithoutCondition_throwsStackOverflow() {
- final AtomicReference<Provider<Object>> doubleCheckReference =
- new AtomicReference<>();
- Provider<Object> doubleCheck = DoubleCheck.provider(() -> doubleCheckReference.get().get());
- doubleCheckReference.set(doubleCheck);
- try {
- doubleCheck.get();
- fail();
- } catch (StackOverflowError expected) {}
- }
-
- @Test public void reentranceReturningSameInstance() {
- final AtomicReference<Provider<Object>> doubleCheckReference =
- new AtomicReference<>();
- final AtomicInteger invocationCount = new AtomicInteger();
- final Object object = new Object();
- Provider<Object> doubleCheck = DoubleCheck.provider(() -> {
- if (invocationCount.incrementAndGet() == 1) {
- doubleCheckReference.get().get();
- }
- return object;
- });
- doubleCheckReference.set(doubleCheck);
- assertThat(doubleCheck.get()).isSameInstanceAs(object);
- }
-
- @Test public void reentranceReturningDifferentInstances_throwsIllegalStateException() {
- final AtomicReference<Provider<Object>> doubleCheckReference =
- new AtomicReference<>();
- final AtomicInteger invocationCount = new AtomicInteger();
- Provider<Object> doubleCheck = DoubleCheck.provider(() -> {
- if (invocationCount.incrementAndGet() == 1) {
- doubleCheckReference.get().get();
- }
- return new Object();
- });
- doubleCheckReference.set(doubleCheck);
- try {
- doubleCheck.get();
- fail();
- } catch (IllegalStateException expected) {}
- }
-
- @Test
- public void instanceFactoryAsLazyDoesNotWrap() {
- Factory<Object> factory = InstanceFactory.create(new Object());
- assertThat(DoubleCheck.lazy(factory)).isSameInstanceAs(factory);
- }
-}
diff --git a/javatests/dagger/internal/InstanceFactoryTest.java b/javatests/dagger/internal/InstanceFactoryTest.java
deleted file mode 100644
index 82b66e6..0000000
--- a/javatests/dagger/internal/InstanceFactoryTest.java
+++ /dev/null
@@ -1,43 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class InstanceFactoryTest {
- @Test public void instanceFactory() {
- Object instance = new Object();
- Factory<Object> factory = InstanceFactory.create(instance);
- assertThat(factory.get()).isEqualTo(instance);
- assertThat(factory.get()).isEqualTo(instance);
- assertThat(factory.get()).isEqualTo(instance);
- }
-
- @Test public void create_throwsNullPointerException() {
- try {
- InstanceFactory.create(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/internal/MapProviderFactoryTest.java b/javatests/dagger/internal/MapProviderFactoryTest.java
deleted file mode 100644
index 5598ff2..0000000
--- a/javatests/dagger/internal/MapProviderFactoryTest.java
+++ /dev/null
@@ -1,80 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SuppressWarnings("unchecked")
-public class MapProviderFactoryTest {
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void nullKey() {
- thrown.expect(NullPointerException.class);
- MapProviderFactory.<String, Integer>builder(1).put(null, incrementingIntegerProvider(1));
- }
-
- @Test
- public void nullValue() {
- thrown.expect(NullPointerException.class);
- MapProviderFactory.<String, Integer>builder(1).put("Hello", null);
- }
-
- @Test
- public void iterationOrder() {
- Provider<Integer> p1 = incrementingIntegerProvider(10);
- Provider<Integer> p2 = incrementingIntegerProvider(20);
- Provider<Integer> p3 = incrementingIntegerProvider(30);
- Provider<Integer> p4 = incrementingIntegerProvider(40);
- Provider<Integer> p5 = incrementingIntegerProvider(50);
-
- Factory<Map<String, Provider<Integer>>> factory = MapProviderFactory
- .<String, Integer>builder(4)
- .put("two", p2)
- .put("one", p1)
- .put("three", p3)
- .put("one", p5)
- .put("four", p4)
- .build();
-
- Map<String, Provider<Integer>> expectedMap = new LinkedHashMap<>();
- expectedMap.put("two", p2);
- expectedMap.put("one", p1);
- expectedMap.put("three", p3);
- expectedMap.put("one", p5);
- expectedMap.put("four", p4);
- assertThat(factory.get().entrySet())
- .containsExactlyElementsIn(expectedMap.entrySet())
- .inOrder();
- }
-
- private static Provider<Integer> incrementingIntegerProvider(int seed) {
- return new AtomicInteger(seed)::getAndIncrement;
- }
-}
diff --git a/javatests/dagger/internal/SetBuilderTest.java b/javatests/dagger/internal/SetBuilderTest.java
deleted file mode 100644
index ac78312..0000000
--- a/javatests/dagger/internal/SetBuilderTest.java
+++ /dev/null
@@ -1,62 +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;
-
-import static org.junit.Assert.fail;
-
-import java.util.Arrays;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SetBuilderTest {
- private SetBuilder<String> setBuilder;
-
- @Before
- public void setUp() {
- setBuilder = SetBuilder.newSetBuilder(1);
- }
-
- @Test
- public void addNull() {
- try {
- setBuilder.add(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Test
- public void addNullCollection() {
- try {
- setBuilder.addAll(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Test
- public void addNullElement() {
- try {
- setBuilder.addAll(Arrays.asList("hello", null, "world"));
- fail();
- } catch (NullPointerException expected) {
- }
- }
-}
diff --git a/javatests/dagger/internal/SetFactoryTest.java b/javatests/dagger/internal/SetFactoryTest.java
deleted file mode 100644
index 0032578..0000000
--- a/javatests/dagger/internal/SetFactoryTest.java
+++ /dev/null
@@ -1,86 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SuppressWarnings("unchecked")
-public class SetFactoryTest {
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void providerReturnsNull() {
- Factory<Set<Integer>> factory =
- SetFactory.<Integer>builder(0, 1).addCollectionProvider(() -> null).build();
- thrown.expect(NullPointerException.class);
- factory.get();
- }
-
- @Test
- public void providerReturnsNullSet() {
- Factory<Set<Integer>> factory =
- SetFactory.<Integer>builder(1, 0).addProvider(() -> null).build();
- thrown.expect(NullPointerException.class);
- factory.get();
- }
-
- @Test
- public void providerReturnsSetWithNullElement() {
- Set<Integer> set = new LinkedHashSet<>(Arrays.asList(1, null, 3));
- Factory<Set<Integer>> factory =
- SetFactory.<Integer>builder(0, 1).addCollectionProvider(() -> set).build();
- thrown.expect(NullPointerException.class);
- factory.get();
- }
-
- @Test
- public void invokesProvidersEveryTime() {
- Factory<Set<Integer>> factory =
- SetFactory.<Integer>builder(2, 2)
- .addProvider(incrementingIntegerProvider(0))
- .addProvider(incrementingIntegerProvider(10))
- .addCollectionProvider(incrementingIntegerSetProvider(20))
- .addCollectionProvider(incrementingIntegerSetProvider(30))
- .build();
- assertThat(factory.get()).containsExactly(0, 10, 20, 21, 30, 31);
- assertThat(factory.get()).containsExactly(1, 11, 22, 23, 32, 33);
- assertThat(factory.get()).containsExactly(2, 12, 24, 25, 34, 35);
- }
-
- private static Provider<Integer> incrementingIntegerProvider(int seed) {
- final AtomicInteger value = new AtomicInteger(seed);
- return value::getAndIncrement;
- }
-
- private static Provider<Set<Integer>> incrementingIntegerSetProvider(int seed) {
- final AtomicInteger value = new AtomicInteger(seed);
- return () -> ImmutableSet.of(value.getAndIncrement(), value.getAndIncrement());
- }
-}
diff --git a/javatests/dagger/internal/SingleCheckTest.java b/javatests/dagger/internal/SingleCheckTest.java
deleted file mode 100644
index 0c043fd..0000000
--- a/javatests/dagger/internal/SingleCheckTest.java
+++ /dev/null
@@ -1,45 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link SingleCheck}.
- */
-@RunWith(JUnit4.class)
-public class SingleCheckTest {
- @Test(expected = NullPointerException.class)
- public void create_nullPointerException() {
- SingleCheck.provider(null);
- }
-
- @Test
- public void get() {
- AtomicInteger integer = new AtomicInteger();
- Provider<Integer> provider = SingleCheck.provider(integer::getAndIncrement);
- assertThat(provider.get()).isEqualTo(0);
- assertThat(provider.get()).isEqualTo(0);
- assertThat(provider.get()).isEqualTo(0);
- }
-}
diff --git a/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java b/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java
deleted file mode 100644
index bb967b1..0000000
--- a/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java
+++ /dev/null
@@ -1,2838 +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 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
deleted file mode 100644
index 1bd221a..0000000
--- a/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsTest.java
+++ /dev/null
@@ -1,5677 +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 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
deleted file mode 100644
index fda5859..0000000
--- a/javatests/dagger/internal/codegen/AnnotationProtoConverterTest.java
+++ /dev/null
@@ -1,97 +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.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/BUILD b/javatests/dagger/internal/codegen/BUILD
deleted file mode 100644
index ad214ff..0000000
--- a/javatests/dagger/internal/codegen/BUILD
+++ /dev/null
@@ -1,56 +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 for the Dagger compiler/codegen
-
-package(default_visibility = ["//:src"])
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
-
-GenJavaTests(
- name = "compiler_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//java/dagger:core",
- "//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:validation",
- "//java/dagger/internal/codegen:writing",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/langmodel",
- "//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", # 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",
- "@google_bazel_common//third_party/java/truth:truth8",
- ],
-)
diff --git a/javatests/dagger/internal/codegen/BindingGraphCapturer.java b/javatests/dagger/internal/codegen/BindingGraphCapturer.java
deleted file mode 100644
index 503fd47..0000000
--- a/javatests/dagger/internal/codegen/BindingGraphCapturer.java
+++ /dev/null
@@ -1,49 +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 com.google.common.collect.ImmutableMap;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-
-/**
- * A testing plugin that captures {@link dagger.model.BindingGraph}s for tests to make assertions
- * about.
- */
-// TODO(dpb): Move to dagger.spi.testing?
-final class BindingGraphCapturer implements BindingGraphPlugin {
-
- private final ImmutableMap.Builder<String, BindingGraph> bindingGraphs = ImmutableMap.builder();
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- bindingGraphs.put(
- bindingGraph
- .rootComponentNode()
- .componentPath()
- .currentComponent()
- .getQualifiedName()
- .toString(),
- bindingGraph);
- }
-
- /** Returns a map of binding graphs, indexed by the canonical name of the root component type. */
- public ImmutableMap<String, BindingGraph> bindingGraphs() {
- return bindingGraphs.build();
- }
-}
diff --git a/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java b/javatests/dagger/internal/codegen/BindsInstanceValidationTest.java
deleted file mode 100644
index 2496d8b..0000000
--- a/javatests/dagger/internal/codegen/BindsInstanceValidationTest.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;
-
-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 BindsInstanceValidationTest {
- @Test
- public void bindsInstanceInModule() {
- JavaFileObject testModule =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @BindsInstance abstract void str(String string);",
- "}");
- Compilation compilation = daggerCompiler().compile(testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@BindsInstance methods should not be included in @Modules. Did you mean @Binds");
- }
-
- @Test
- public void bindsInstanceInComponent() {
- JavaFileObject testComponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " @BindsInstance String s(String s);",
- "}");
- Compilation compilation = daggerCompiler().compile(testComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@BindsInstance methods should not be included in @Components. "
- + "Did you mean to put it in a @Component.Builder?");
- }
-
- @Test
- public void bindsInstanceNotAbstract() {
- JavaFileObject notAbstract =
- JavaFileObjects.forSourceLines(
- "test.BindsInstanceNotAbstract",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "class BindsInstanceNotAbstract {",
- " @BindsInstance BindsInstanceNotAbstract bind(int unused) { return this; }",
- "}");
- Compilation compilation = daggerCompiler().compile(notAbstract);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@BindsInstance methods must be abstract")
- .inFile(notAbstract)
- .onLine(7);
- }
-
- @Test
- public void bindsInstanceNoParameters() {
- JavaFileObject notAbstract =
- JavaFileObjects.forSourceLines(
- "test.BindsInstanceNoParameters",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "",
- "interface BindsInstanceNoParameters {",
- " @BindsInstance void noParams();",
- "}");
- Compilation compilation = daggerCompiler().compile(notAbstract);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@BindsInstance methods should have exactly one parameter for the bound type")
- .inFile(notAbstract)
- .onLine(6);
- }
-
- @Test
- public void bindsInstanceManyParameters() {
- JavaFileObject notAbstract =
- JavaFileObjects.forSourceLines(
- "test.BindsInstanceNoParameter",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "",
- "interface BindsInstanceManyParameters {",
- " @BindsInstance void manyParams(int i, long l);",
- "}");
- Compilation compilation = daggerCompiler().compile(notAbstract);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@BindsInstance methods should have exactly one parameter for the bound type")
- .inFile(notAbstract)
- .onLine(6);
- }
-
- @Test
- public void bindsInstanceFrameworkType() {
- JavaFileObject bindsFrameworkType =
- JavaFileObjects.forSourceLines(
- "test.BindsInstanceFrameworkType",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.producers.Producer;",
- "import javax.inject.Provider;",
- "",
- "interface BindsInstanceFrameworkType {",
- " @BindsInstance void bindsProvider(Provider<Object> objectProvider);",
- " @BindsInstance void bindsProducer(Producer<Object> objectProducer);",
- "}");
- Compilation compilation = daggerCompiler().compile(bindsFrameworkType);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@BindsInstance parameters must not be framework types")
- .inFile(bindsFrameworkType)
- .onLine(8);
-
- assertThat(compilation)
- .hadErrorContaining("@BindsInstance parameters must not be framework types")
- .inFile(bindsFrameworkType)
- .onLine(9);
- }
-
-}
diff --git a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
deleted file mode 100644
index 6ba9e3e..0000000
--- a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
+++ /dev/null
@@ -1,157 +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;
-
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.common.collect.ImmutableList;
-import dagger.Module;
-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;
-import javax.inject.Qualifier;
-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 BindsMethodValidationTest {
- @Parameters
- public static Collection<Object[]> data() {
- return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}});
- }
-
- private final String moduleDeclaration;
-
- public BindsMethodValidationTest(Class<? extends Annotation> moduleAnnotation) {
- moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }";
- }
-
- @Test
- public void nonAbstract() {
- assertThatMethod("@Binds Object concrete(String impl) { return null; }")
- .hasError("must be abstract");
- }
-
- @Test
- public void notAssignable() {
- assertThatMethod("@Binds abstract String notAssignable(Object impl);").hasError("assignable");
- }
-
- @Test
- public void moreThanOneParameter() {
- assertThatMethod("@Binds abstract Object tooManyParameters(String s1, String s2);")
- .hasError("one parameter");
- }
-
- @Test
- public void typeParameters() {
- assertThatMethod("@Binds abstract <S, T extends S> S generic(T t);")
- .hasError("type parameters");
- }
-
- @Test
- public void notInModule() {
- assertThatMethodInUnannotatedClass("@Binds abstract Object bindObject(String s);")
- .hasError("within a @Module or @ProducerModule");
- }
-
- @Test
- public void throwsException() {
- assertThatMethod("@Binds abstract Object throwsException(String s1) throws IOException;")
- .importing(IOException.class)
- .hasError("only throw unchecked");
- }
-
- @Test
- public void returnsVoid() {
- assertThatMethod("@Binds abstract void returnsVoid(Object impl);").hasError("void");
- }
-
- @Test
- public void tooManyQualifiersOnMethod() {
- assertThatMethod(
- "@Binds @Qualifier1 @Qualifier2 abstract String tooManyQualifiers(String impl);")
- .importing(Qualifier1.class, Qualifier2.class)
- .hasError("more than one @Qualifier");
- }
-
- @Test
- public void tooManyQualifiersOnParameter() {
- assertThatMethod(
- "@Binds abstract String tooManyQualifiers(@Qualifier1 @Qualifier2 String impl);")
- .importing(Qualifier1.class, Qualifier2.class)
- .hasError("more than one @Qualifier");
- }
-
- @Test
- public void noParameters() {
- assertThatMethod("@Binds abstract Object noParameters();").hasError("one parameter");
- }
-
- @Test
- public void setElementsNotAssignable() {
- assertThatMethod(
- "@Binds @ElementsIntoSet abstract Set<String> bindSetOfIntegers(Set<Integer> ints);")
- .hasError("assignable");
- }
-
- @Test
- public void setElements_primitiveArgument() {
- assertThatMethod("@Binds @ElementsIntoSet abstract Set<Number> bindInt(int integer);")
- .hasError("assignable");
- }
-
- @Test
- public void elementsIntoSet_withRawSets() {
- assertThatMethod("@Binds @ElementsIntoSet abstract Set bindRawSet(HashSet hashSet);")
- .hasError("cannot return a raw Set");
- }
-
- @Test
- public void intoMap_noMapKey() {
- assertThatMethod("@Binds @IntoMap abstract Object bindNoMapKey(String string);")
- .hasError("methods of type map must declare a map key");
- }
-
- @Test
- public void intoMap_multipleMapKeys() {
- assertThatMethod(
- "@Binds @IntoMap @IntKey(1) @LongKey(2L) abstract Object manyMapKeys(String string);")
- .importing(IntKey.class, LongKey.class)
- .hasError("may not have more than one map key");
- }
-
- private DaggerModuleMethodSubject assertThatMethod(String method) {
- return assertThatModuleMethod(method).withDeclaration(moduleDeclaration);
- }
-
- @Qualifier
- @Retention(RUNTIME)
- public @interface Qualifier1 {}
-
- @Qualifier
- @Retention(RUNTIME)
- public @interface Qualifier2 {}
-}
diff --git a/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java b/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java
deleted file mode 100644
index 28b75be..0000000
--- a/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java
+++ /dev/null
@@ -1,216 +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;
-
-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;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests that errors are reported correctly when a {@code @Binds} method's delegate (the type of its
- * parameter) is missing.
- */
-@RunWith(JUnit4.class)
-public class BindsMissingDelegateValidationTest {
- @Test
- public void bindsMissingDelegate() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "",
- "@Component(modules = C.TestModule.class)",
- "interface C {",
- " Object object();",
- "",
- " static class NotBound {}",
- "",
- " @Module",
- " abstract static class TestModule {",
- " @Binds abstract Object bindObject(NotBound notBound);",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.C.NotBound cannot be provided")
- .inFile(component)
- .onLineContaining("interface C");
- }
-
- @Test
- public void bindsMissingDelegate_duplicateBinding() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Component(modules = C.TestModule.class)",
- "interface C {",
- " Object object();",
- "",
- " static class NotBound {}",
- "",
- " @Module",
- " abstract static class TestModule {",
- " @Binds abstract Object bindObject(NotBound notBound);",
- " @Provides static Object provideObject() { return new Object(); }",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- // Some javacs report only the first error for each source line.
- // Assert that one of the expected errors is reported.
- assertThat(compilation)
- .hadErrorContainingMatch(
- "\\Qtest.C.NotBound cannot be provided\\E|"
- + message(
- "\\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)
- .onLineContaining("interface C");
- }
-
- @Test
- public void bindsMissingDelegate_setBinding() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "",
- "@Component(modules = C.TestModule.class)",
- "interface C {",
- " Set<Object> objects();",
- "",
- " static class NotBound {}",
- "",
- " @Module",
- " abstract static class TestModule {",
- " @Binds @IntoSet abstract Object bindObject(NotBound notBound);",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.C.NotBound cannot be provided")
- .inFile(component)
- .onLineContaining("interface C");
- }
-
- @Test
- public void bindsMissingDelegate_mapBinding() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.Map;",
- "",
- "@Component(modules = C.TestModule.class)",
- "interface C {",
- " Map<String, Object> objects();",
- "",
- " static class NotBound {}",
- "",
- " @Module",
- " abstract static class TestModule {",
- " @Binds @IntoMap @StringKey(\"key\")",
- " abstract Object bindObject(NotBound notBound);",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.C.NotBound cannot be provided")
- .inFile(component)
- .onLineContaining("interface C");
- }
-
- @Test
- public void bindsMissingDelegate_mapBinding_sameKey() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.Map;",
- "",
- "@Component(modules = C.TestModule.class)",
- "interface C {",
- " Map<String, Object> objects();",
- "",
- " static class NotBound {}",
- "",
- " @Module",
- " abstract static class TestModule {",
- " @Binds @IntoMap @StringKey(\"key\")",
- " abstract Object bindObject(NotBound notBound);",
- "",
- " @Provides @IntoMap @StringKey(\"key\")",
- " static Object provideObject() { return new Object(); }",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- // Some javacs report only the first error for each source line.
- assertThat(compilation)
- .hadErrorContainingMatch(
- "\\Qtest.C.NotBound cannot be provided\\E|"
- + "\\Qsame map key is bound more than once\\E")
- .inFile(component)
- .onLineContaining("interface C");
- }
-}
diff --git a/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java
deleted file mode 100644
index fa44a6e..0000000
--- a/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java
+++ /dev/null
@@ -1,189 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
-
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests {@link BindsOptionalOfMethodValidator}. */
-@RunWith(Parameterized.class)
-public class BindsOptionalOfMethodValidationTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> data() {
- return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}});
- }
-
- private final String moduleDeclaration;
-
- public BindsOptionalOfMethodValidationTest(Class<? extends Annotation> moduleAnnotation) {
- moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }";
- }
-
- @Test
- public void nonAbstract() {
- assertThatMethod("@BindsOptionalOf Object concrete() { return null; }")
- .hasError("must be abstract");
- }
-
- @Test
- public void hasParameters() {
- assertThatMethod("@BindsOptionalOf abstract Object hasParameters(String s1);")
- .hasError("parameters");
- }
-
- @Test
- public void typeParameters() {
- assertThatMethod("@BindsOptionalOf abstract <S> S generic();").hasError("type parameters");
- }
-
- @Test
- public void notInModule() {
- assertThatMethodInUnannotatedClass("@BindsOptionalOf abstract Object notInModule();")
- .hasError("within a @Module or @ProducerModule");
- }
-
- @Test
- public void throwsException() {
- assertThatMethod("@BindsOptionalOf abstract Object throwsException() throws RuntimeException;")
- .hasError("may not throw");
- }
-
- @Test
- public void returnsVoid() {
- assertThatMethod("@BindsOptionalOf abstract void returnsVoid();").hasError("void");
- }
-
- @Test
- public void returnsMembersInjector() {
- assertThatMethod("@BindsOptionalOf abstract MembersInjector<Object> returnsMembersInjector();")
- .hasError("framework");
- }
-
- @Test
- public void tooManyQualifiers() {
- assertThatMethod(
- "@BindsOptionalOf @Qualifier1 @Qualifier2 abstract String tooManyQualifiers();")
- .importing(Qualifier1.class, Qualifier2.class)
- .hasError("more than one @Qualifier");
- }
-
- @Test
- public void intoSet() {
- assertThatMethod("@BindsOptionalOf @IntoSet abstract String intoSet();")
- .hasError("cannot have multibinding annotations");
- }
-
- @Test
- public void elementsIntoSet() {
- assertThatMethod("@BindsOptionalOf @ElementsIntoSet abstract Set<String> elementsIntoSet();")
- .hasError("cannot have multibinding annotations");
- }
-
- @Test
- public void intoMap() {
- assertThatMethod("@BindsOptionalOf @IntoMap abstract String intoMap();")
- .hasError("cannot have multibinding annotations");
- }
-
- /**
- * Tests that @BindsOptionalOf @IntoMap actually causes module validation to fail.
- *
- * @see <a href="http://b/118434447">bug 118434447</a>
- */
- @Test
- public void intoMapWithComponent() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.BindsOptionalOf;",
- "import dagger.Module;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "interface TestModule {",
- " @BindsOptionalOf @IntoMap Object object();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {}");
-
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cannot have multibinding annotations")
- .inFile(module)
- .onLineContaining("object();");
- }
-
- /** An injectable value object. */
- public static final class Thing {
- @Inject
- Thing() {}
- }
-
- @Test
- public void implicitlyProvidedType() {
- assertThatMethod("@BindsOptionalOf abstract Thing thing();")
- .importing(Thing.class)
- .hasError("return unqualified types that have an @Inject-annotated constructor");
- }
-
- @Test
- public void hasScope() {
- assertThatMethod("@BindsOptionalOf @Singleton abstract String scoped();")
- .importing(Singleton.class)
- .hasError("cannot be scoped");
- }
-
- private DaggerModuleMethodSubject assertThatMethod(String method) {
- return assertThatModuleMethod(method).withDeclaration(moduleDeclaration);
- }
-
- /** A qualifier. */
- @Qualifier
- public @interface Qualifier1 {}
-
- /** A qualifier. */
- @Qualifier
- public @interface Qualifier2 {}
-}
diff --git a/javatests/dagger/internal/codegen/CompilerMode.java b/javatests/dagger/internal/codegen/CompilerMode.java
deleted file mode 100644
index 23aa312..0000000
--- a/javatests/dagger/internal/codegen/CompilerMode.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;
-
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-
-/** The configuration options for compiler modes. */
-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"),
- ;
-
- /** Returns the compiler modes as a list of parameters for parameterized tests */
- static final ImmutableList<Object[]> TEST_PARAMETERS =
- ImmutableList.copyOf(
- new Object[][] {{CompilerMode.DEFAULT_MODE}, {CompilerMode.FAST_INIT_MODE}});
-
- private final ImmutableList<String> javacopts;
-
- private CompilerMode(String... javacopts) {
- this.javacopts = ImmutableList.copyOf(javacopts);
- }
-
- /** Returns the javacopts for this compiler mode. */
- FluentIterable<String> javacopts() {
- return FluentIterable.from(javacopts);
- }
-
- /**
- * Returns a {@link JavaFileBuilder} that builds {@link javax.tools.JavaFileObject}s for this
- * mode.
- */
- JavaFileBuilder javaFileBuilder(String qualifiedName) {
- return new JavaFileBuilder(this, qualifiedName);
- }
-}
diff --git a/javatests/dagger/internal/codegen/Compilers.java b/javatests/dagger/internal/codegen/Compilers.java
deleted file mode 100644
index 3e08f63..0000000
--- a/javatests/dagger/internal/codegen/Compilers.java
+++ /dev/null
@@ -1,60 +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;
-
-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.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 javax.annotation.processing.Processor;
-
-/** {@link Compiler} instances for testing Dagger. */
-final class Compilers {
- private static final String GUAVA = "guava";
-
- 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.
- */
- 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());
- }
-
- static Compiler compilerWithOptions(CompilerMode... compilerModes) {
- FluentIterable<String> options = FluentIterable.of();
- for (CompilerMode compilerMode : compilerModes) {
- options = options.append(compilerMode.javacopts());
- }
- return daggerCompiler().withOptions(options);
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentBuilderTest.java b/javatests/dagger/internal/codegen/ComponentBuilderTest.java
deleted file mode 100644
index f280bdd..0000000
--- a/javatests/dagger/internal/codegen/ComponentBuilderTest.java
+++ /dev/null
@@ -1,365 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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 java.util.Collection;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for {@link dagger.Component.Builder} */
-@RunWith(Parameterized.class)
-public class ComponentBuilderTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ComponentBuilderTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- private static final ErrorMessages.ComponentCreatorMessages MSGS =
- creatorMessagesFor(COMPONENT_BUILDER);
-
- @Test
- public void testUsesBuildAndSetterNames() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String string() { return null; }",
- "}");
-
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " String string();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " Builder setTestModule(TestModule testModule);",
- " TestComponent create();",
- " }",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private static final class Builder implements TestComponent.Builder {",
- " private TestModule testModule;",
- "",
- " @Override",
- " public Builder setTestModule(TestModule testModule) {",
- " this.testModule = Preconditions.checkNotNull(testModule);",
- " return this;",
- " }",
- "",
- " @Override",
- " public TestComponent create() {",
- " if (testModule == null) {",
- " this.testModule = new TestModule();",
- " }",
- " return new DaggerTestComponent(testModule);",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void testSetterMethodWithMoreThanOneArgFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " Builder set(String s, Integer i);",
- " Builder set(Number n, Double d);",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
- .inFile(componentFile)
- .onLineContaining("Builder set(String s, Integer i);");
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
- .inFile(componentFile)
- .onLineContaining("Builder set(Number n, Double d);");
- }
-
- @Test
- public void testInheritedSetterMethodWithMoreThanOneArgFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " SimpleComponent build();",
- " Builder set1(String s, Integer i);",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- MSGS.inheritedSetterMethodsMustTakeOneArg(),
- "set1(java.lang.String,java.lang.Integer)"))
- .inFile(componentFile)
- .onLineContaining("interface Builder");
- }
-
- @Test
- public void testSetterReturningNonVoidOrBuilderFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " String set(Integer i);",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder())
- .inFile(componentFile)
- .onLineContaining("String set(Integer i);");
- }
-
- @Test
- public void testInheritedSetterReturningNonVoidOrBuilderFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " SimpleComponent build();",
- " String set(Integer i);",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- MSGS.inheritedSetterMethodsMustReturnVoidOrBuilder(), "set(java.lang.Integer)"))
- .inFile(componentFile)
- .onLineContaining("interface Builder");
- }
-
- @Test
- public void testGenericsOnSetterMethodFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " <T> Builder set(T t);",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
- .inFile(componentFile)
- .onLineContaining("<T> Builder set(T t);");
- }
-
- @Test
- public void testGenericsOnInheritedSetterMethodFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " SimpleComponent build();",
- " <T> Builder set(T t);",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
- .inFile(componentFile)
- .onLineContaining("interface Builder");
- }
-
- @Test
- public void testBindsInstanceNotAllowedOnBothSetterAndParameter() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " abstract String s();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance",
- " Builder s(@BindsInstance String s);",
- "",
- " SimpleComponent build();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.bindsInstanceNotAllowedOnBothSetterMethodAndParameter())
- .inFile(componentFile)
- .onLineContaining("Builder s(");
- }
-
- @Test
- public void testBindsInstanceNotAllowedOnBothSetterAndParameter_inherited() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " abstract String s();",
- "",
- " interface BuilderParent<B extends BuilderParent> {",
- " @BindsInstance",
- " B s(@BindsInstance String s);",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends BuilderParent<Builder> {",
- " SimpleComponent build();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- MSGS.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter(),
- "s(java.lang.String)"))
- .inFile(componentFile)
- .onLineContaining("Builder extends BuilderParent<Builder>");
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTest.java b/javatests/dagger/internal/codegen/ComponentCreatorTest.java
deleted file mode 100644
index 6f4ea8d..0000000
--- a/javatests/dagger/internal/codegen/ComponentCreatorTest.java
+++ /dev/null
@@ -1,1253 +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;
-
-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.daggerCompiler;
-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 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 java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for properties of component creators shared by both builders and factories. */
-@RunWith(Parameterized.class)
-public class ComponentCreatorTest extends ComponentCreatorTestHelper {
- @Parameters(name = "compilerMode={0}, creatorKind={1}")
- public static Collection<Object[]> parameters() {
- 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) {
- super(compilerMode, componentCreatorAnnotation);
- }
-
- @Test
- public void testEmptyCreator() {
- JavaFileObject injectableTypeFile =
- JavaFileObjects.forSourceLines(
- "test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectableType someInjectableType();",
- "",
- " @Component.Builder",
- " static interface Builder {",
- " SimpleComponent build();",
- " }",
- "}");
- JavaFileObject generatedComponent =
- preprocessedJavaFile(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private static final class Builder implements SimpleComponent.Builder {",
- " @Override",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "}");
- Compilation compilation = compile(injectableTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void testCanInstantiateModulesUserCannotSet() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String string() { return null; }",
- "}");
-
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " String string();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " TestComponent build();",
- " }",
- "}");
- JavaFileObject generatedComponent =
- preprocessedJavaFile(
- "test.DaggerTestComponent",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final TestModule testModule;",
- "",
- " private DaggerTestComponent(TestModule testModuleParam) {",
- " this.testModule = testModuleParam;",
- " }",
- "",
- " public static TestComponent.Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public String string() {",
- " return TestModule_StringFactory.string(testModule);",
- " }",
- "",
- " private static final class Builder implements TestComponent.Builder {",
- " @Override",
- " public TestComponent build() {",
- " return new DaggerTestComponent(new TestModule());",
- " }",
- " }",
- "}");
- Compilation compilation = compile(module, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void testMoreThanOneCreatorOfSameTypeFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " @Component.Builder",
- " static interface Builder {",
- " SimpleComponent build();",
- " }",
- "",
- " @Component.Builder",
- " interface Builder2 {",
- " SimpleComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- componentMessagesFor(COMPONENT).moreThanOne(),
- process("[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]")))
- .inFile(componentFile);
- }
-
- @Test
- public void testBothBuilderAndFactoryFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " @Component.Builder",
- " static interface Builder {",
- " SimpleComponent build();",
- " }",
- "",
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- componentMessagesFor(COMPONENT).moreThanOne(),
- "[test.SimpleComponent.Builder, test.SimpleComponent.Factory]"))
- .inFile(componentFile);
- }
-
- @Test
- public void testGenericCreatorTypeFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " @Component.Builder",
- " interface Builder<T> {",
- " SimpleComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.generics()).inFile(componentFile);
- }
-
- @Test
- public void testCreatorNotInComponentFails() {
- JavaFileObject builder =
- preprocessedJavaFile(
- "test.Builder",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component.Builder",
- "interface Builder {}");
- Compilation compilation = compile(builder);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.mustBeInComponent()).inFile(builder);
- }
-
- @Test
- public void testCreatorMissingFactoryMethodFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " @Component.Builder",
- " interface Builder {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.missingFactoryMethod())
- .inFile(componentFile);
- }
-
- @Test
- public void testCreatorWithBindsInstanceNoStaticCreateGenerated() {
- JavaFileObject componentFile =
- javaFileBuilder("test.SimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " Object object();",
- "")
- .addLinesIf(
- BUILDER,
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder object(Object object);",
- " SimpleComponent build();",
- " }")
- .addLinesIf(
- FACTORY,
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create(@BindsInstance Object object);",
- " }")
- .addLines("}")
- .build();
-
- JavaFileObject generatedComponent =
- javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private final Object object;",
- "",
- " private DaggerSimpleComponent(Object objectParam) {",
- " this.object = objectParam;",
- " }",
- "")
- .addLinesIf(
- BUILDER,
- " public static SimpleComponent.Builder builder() {",
- " return new Builder();",
- " }")
- .addLinesIf(
- FACTORY,
- " public static SimpleComponent.Factory factory() {",
- " return new Factory();",
- " }")
- .addLines(
- "", //
- " @Override",
- " public Object object() {",
- " return object;",
- " }",
- "")
- .addLinesIf(
- BUILDER,
- " private static final class Builder implements SimpleComponent.Builder {",
- " private Object object;",
- "",
- " @Override",
- " public Builder object(Object object) {",
- " this.object = Preconditions.checkNotNull(object);",
- " return this;",
- " }",
- "",
- " @Override",
- " public SimpleComponent build() {",
- " Preconditions.checkBuilderRequirement(object, Object.class);",
- " return new DaggerSimpleComponent(object);",
- " }",
- " }")
- .addLinesIf(
- FACTORY,
- " private static final class Factory implements SimpleComponent.Factory {",
- " @Override",
- " public SimpleComponent create(Object object) {",
- " Preconditions.checkNotNull(object);",
- " return new DaggerSimpleComponent(object);",
- " }",
- " }")
- .addLines("}")
- .build();
-
- Compilation compilation = compile(componentFile);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void testCreatorWithPrimitiveBindsInstance() {
- JavaFileObject componentFile =
- javaFileBuilder("test.SimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " int anInt();",
- "")
- .addLinesIf(
- BUILDER,
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder i(int i);",
- " SimpleComponent build();",
- " }")
- .addLinesIf(
- FACTORY,
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create(@BindsInstance int i);",
- " }")
- .addLines(
- "}")
- .build();
-
- JavaFileObject generatedComponent =
- javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private final Integer i;",
- "",
- " private DaggerSimpleComponent(Integer iParam) {",
- " this.i = iParam;",
- " }",
- "",
- " @Override",
- " public int anInt() {",
- " return i;",
- " }",
- "")
- .addLinesIf(
- BUILDER,
- " private static final class Builder implements SimpleComponent.Builder {",
- " private Integer i;",
- "",
- " @Override",
- " public Builder i(int i) {",
- " this.i = Preconditions.checkNotNull(i);",
- " return this;",
- " }",
- "",
- " @Override",
- " public SimpleComponent build() {",
- " Preconditions.checkBuilderRequirement(i, Integer.class);",
- " return new DaggerSimpleComponent(i);",
- " }",
- " }")
- .addLinesIf(
- FACTORY,
- " private static final class Factory implements SimpleComponent.Factory {",
- " @Override",
- " public SimpleComponent create(int i) {",
- " Preconditions.checkNotNull(i);",
- " return new DaggerSimpleComponent(i);",
- " }",
- " }")
- .addLines(
- "}")
- .build();
-
- Compilation compilation = compile(componentFile);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void testPrivateCreatorFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " private interface Builder {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.isPrivate()).inFile(componentFile);
- }
-
- @Test
- public void testNonStaticCreatorFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " abstract class Builder {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.mustBeStatic()).inFile(componentFile);
- }
-
- @Test
- public void testNonAbstractCreatorFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " static class Builder {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.mustBeAbstract()).inFile(componentFile);
- }
-
- @Test
- public void testCreatorOneConstructorWithArgsFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " static abstract class Builder {",
- " Builder(String unused) {}",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.invalidConstructor())
- .inFile(componentFile);
- }
-
- @Test
- public void testCreatorMoreThanOneConstructorFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " static abstract class Builder {",
- " Builder() {}",
- " Builder(String unused) {}",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.invalidConstructor())
- .inFile(componentFile);
- }
-
- @Test
- public void testCreatorEnumFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " enum Builder {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.mustBeClassOrInterface())
- .inFile(componentFile);
- }
-
- @Test
- public void testCreatorFactoryMethodReturnsWrongTypeFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " String build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.factoryMethodMustReturnComponentType())
- .inFile(componentFile)
- .onLineContaining(process("String build();"));
- }
-
- @Test
- public void testCreatorSetterForNonBindsInstancePrimitiveFails() {
- JavaFileObject component =
- javaFileBuilder("test.TestComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " Object object();",
- "")
- .addLinesIf(
- BUILDER,
- " @Component.Builder",
- " interface Builder {",
- " Builder primitive(long l);",
- " TestComponent build();",
- " }")
- .addLinesIf(
- FACTORY,
- " @Component.Factory",
- " interface Factory {",
- " TestComponent create(long l);",
- " }")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(component);
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContaining(messages.nonBindsInstanceParametersMayNotBePrimitives())
- .inFile(component)
- .onLineContaining("(long l)");
- }
-
- @Test
- public void testInheritedBuilderBuildReturnsWrongTypeFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " String build();",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.inheritedFactoryMethodMustReturnComponentType(), process("build")))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void testTwoFactoryMethodsFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " SimpleComponent newSimpleComponent();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(String.format(messages.twoFactoryMethods(), process("build")))
- .inFile(componentFile)
- .onLineContaining("SimpleComponent newSimpleComponent();");
- }
-
- @Test
- public void testInheritedTwoFactoryMethodsFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " SimpleComponent build();",
- " SimpleComponent newSimpleComponent();",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.inheritedTwoFactoryMethods(), process("build()"), "newSimpleComponent()"))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void testMultipleSettersPerTypeFails() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String s() { return \"\"; }",
- "}");
- JavaFileObject componentFile =
- javaFileBuilder("test.SimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "abstract class SimpleComponent {",
- " abstract String s();",
- "")
- .addLinesIf(
- BUILDER,
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " void set1(TestModule s);",
- " void set2(TestModule s);",
- " }")
- .addLinesIf(
- FACTORY,
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create(TestModule m1, TestModule m2);",
- " }")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(moduleFile, componentFile);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(BUILDER)
- ? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
- + "void test.SimpleComponent.Builder.set2(test.TestModule)]"
- : "[test.TestModule m1, test.TestModule m2]";
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String s() { return \"\"; }",
- "}");
- JavaFileObject componentFile =
- javaFileBuilder("test.SimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "abstract class SimpleComponent {",
- " abstract String s();",
- "")
- .addLinesIf(
- BUILDER,
- " interface Parent<T> {",
- " void set1(T t);",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent<TestModule> {",
- " SimpleComponent build();",
- " void set2(TestModule s);",
- " }")
- .addLinesIf(
- FACTORY,
- " interface Parent<C, T> {",
- " C create(TestModule m1, T t);",
- " }",
- "",
- " @Component.Factory",
- " interface Factory extends Parent<SimpleComponent, TestModule> {}")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(moduleFile, componentFile);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(BUILDER)
- ? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
- + "void test.SimpleComponent.Builder.set2(test.TestModule)]"
- : "[test.TestModule m1, test.TestModule t]";
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void testExtraSettersFails() {
- JavaFileObject componentFile =
- javaFileBuilder("test.SimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = AbstractModule.class)",
- "abstract class SimpleComponent {")
- .addLinesIf(
- BUILDER,
- " @Component.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " void abstractModule(AbstractModule abstractModule);",
- " void other(String s);",
- " }")
- .addLinesIf(
- FACTORY,
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create(AbstractModule abstractModule, String s);",
- " }")
- .addLines("}")
- .build();
- JavaFileObject abstractModule =
- JavaFileObjects.forSourceLines(
- "test.AbstractModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class AbstractModule {}");
- Compilation compilation = compile(componentFile, abstractModule);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(BUILDER)
- ? "[void test.SimpleComponent.Builder.abstractModule(test.AbstractModule), "
- + "void test.SimpleComponent.Builder.other(String)]"
- : "[test.AbstractModule abstractModule, String s]";
- assertThat(compilation)
- .hadErrorContaining(String.format(messages.extraSetters(), elements))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void testMissingSettersFail() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " TestModule(String unused) {}",
- " @Provides String s() { return null; }",
- "}");
- JavaFileObject module2File =
- JavaFileObjects.forSourceLines(
- "test.Test2Module",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class Test2Module {",
- " @Provides Integer i() { return null; }",
- "}");
- JavaFileObject module3File =
- JavaFileObjects.forSourceLines(
- "test.Test3Module",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class Test3Module {",
- " Test3Module(String unused) {}",
- " @Provides Double d() { return null; }",
- "}");
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = {TestModule.class, Test2Module.class, Test3Module.class},",
- " dependencies = OtherComponent.class)",
- "interface TestComponent {",
- " String string();",
- " Integer integer();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " TestComponent create();",
- " }",
- "}");
- JavaFileObject otherComponent =
- JavaFileObjects.forSourceLines(
- "test.OtherComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface OtherComponent {}");
- Compilation compilation =
- daggerCompiler()
- .compile(moduleFile, module2File, module3File, componentFile, otherComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- // Ignores Test2Module because we can construct it ourselves.
- // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
- String.format(
- messages.missingSetters(),
- "[test.TestModule, test.Test3Module, test.OtherComponent]"))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-
- @Test
- public void covariantFactoryMethodReturnType() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject component =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface HasSupertype extends Supertype {",
- " @Component.Builder",
- " interface Builder {",
- " Supertype build();",
- " }",
- "}");
-
- Compilation compilation = compile(foo, supertype, component);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void covariantFactoryMethodReturnType_hasNewMethod() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject component =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface HasSupertype extends Supertype {",
- " Bar bar();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " Supertype build();",
- " }",
- "}");
-
- Compilation compilation = compile(foo, bar, supertype, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining(
- process(
- "test.HasSupertype.Builder.build() returns test.Supertype, but test.HasSupertype "
- + "declares additional component method(s): bar(). In order to provide "
- + "type-safe access to these methods, override build() to return "
- + "test.HasSupertype"))
- .inFile(component)
- .onLine(11);
- }
-
- @Test
- public void covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject creatorSupertype =
- preprocessedJavaFile(
- "test.CreatorSupertype",
- "package test;",
- "",
- "interface CreatorSupertype {",
- " Supertype build();",
- "}");
-
- JavaFileObject component =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface HasSupertype extends Supertype {",
- " Bar bar();",
- "",
- " @Component.Builder",
- " interface Builder extends CreatorSupertype {}",
- "}");
-
- Compilation compilation = compile(foo, bar, supertype, creatorSupertype, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining(
- process(
- "test.HasSupertype.Builder.build() returns test.Supertype, but test.HasSupertype "
- + "declares additional component method(s): bar(). In order to provide "
- + "type-safe access to these methods, override build() to return "
- + "test.HasSupertype"));
- }
-
- @Test
- public void testGenericsOnFactoryMethodFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Builder",
- " interface Builder {",
- " <T> SimpleComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.methodsMayNotHaveTypeParameters())
- .inFile(componentFile)
- .onLineContaining(process("<T> SimpleComponent build();"));
- }
-
- @Test
- public void testGenericsOnInheritedFactoryMethodFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " <T> SimpleComponent build();",
- " }",
- "",
- " @Component.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.inheritedMethodsMayNotHaveTypeParameters(), process("<T>build()")))
- .inFile(componentFile)
- .onLineContaining(process("interface Builder"));
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
deleted file mode 100644
index 2ee120e..0000000
--- a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
+++ /dev/null
@@ -1,89 +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 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 java.util.Arrays;
-import java.util.stream.Stream;
-import javax.tools.JavaFileObject;
-
-/**
- * Base class for component creator codegen tests that are written in terms of builders and
- * transformed, either by automatic string processing or using a {@code JavaFileBuilder}, to test
- * factories as well.
- */
-abstract class ComponentCreatorTestHelper {
-
- private final CompilerMode compilerMode;
-
- protected final ComponentCreatorKind creatorKind;
- protected final ErrorMessages.ComponentCreatorMessages messages;
-
- ComponentCreatorTestHelper(
- CompilerMode compilerMode, ComponentCreatorAnnotation componentCreatorAnnotation) {
- this.compilerMode = compilerMode;
- this.creatorKind = componentCreatorAnnotation.creatorKind();
- this.messages = creatorMessagesFor(componentCreatorAnnotation);
- }
-
- // For tests where code for both builders and factories can be largely equivalent, i.e. when there
- // is nothing to set, just preprocess the lines to change code written for a builder to code for a
- // factory.
- // For more complicated code, use a JavaFileBuilder to add different code depending on the creator
- // kind.
-
- /**
- * Processes the given lines, replacing builder-related names with factory-related names if the
- * creator kind is {@code FACTORY}.
- */
- String process(String... lines) {
- Stream<String> stream = Arrays.stream(lines);
- if (creatorKind.equals(FACTORY)) {
- stream =
- stream.map(
- line ->
- line.replace("Builder", "Factory")
- .replace("builder", "factory")
- .replace("build", "create"));
- }
- return stream.collect(joining("\n"));
- }
-
- /**
- * Returns a Java file with the {@linkplain #process(String...)} processed} versions of the given
- * lines.
- */
- JavaFileObject preprocessedJavaFile(String fullyQualifiedName, String... lines) {
- return JavaFileObjects.forSourceString(fullyQualifiedName, process(lines));
- }
-
- /** Returns a file builder for the current creator kind. */
- JavaFileBuilder javaFileBuilder(String qualifiedName) {
- return new JavaFileBuilder(qualifiedName).withSettings(compilerMode, creatorKind);
- }
-
- /** Compiles the given files with the set compiler mode's javacopts. */
- Compilation compile(JavaFileObject... files) {
- return daggerCompiler().withOptions(compilerMode.javacopts()).compile(files);
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentFactoryTest.java b/javatests/dagger/internal/codegen/ComponentFactoryTest.java
deleted file mode 100644
index 403498b..0000000
--- a/javatests/dagger/internal/codegen/ComponentFactoryTest.java
+++ /dev/null
@@ -1,162 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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 java.util.Collection;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for {@link dagger.Component.Factory} */
-@RunWith(Parameterized.class)
-public class ComponentFactoryTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ComponentFactoryTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- private static final ErrorMessages.ComponentCreatorMessages MSGS =
- creatorMessagesFor(COMPONENT_FACTORY);
-
- @Test
- public void testUsesParameterNames() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String string() { return null; }",
- "}");
-
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " String string();",
- "",
- " @Component.Factory",
- " interface Factory {",
- " TestComponent newTestComponent(TestModule mod);",
- " }",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private static final class Factory implements TestComponent.Factory {",
- " @Override",
- " public TestComponent newTestComponent(TestModule mod) {",
- " Preconditions.checkNotNull(mod);",
- " return new DaggerTestComponent(mod);",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void testSetterMethodFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " @Component.Factory",
- " interface Factory {",
- " SimpleComponent create();",
- " Factory set(String s);",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(String.format(MSGS.twoFactoryMethods(), "create()"))
- .inFile(componentFile)
- .onLineContaining("Factory set(String s);");
- }
-
- @Test
- public void testInheritedSetterMethodFails() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "abstract class SimpleComponent {",
- " interface Parent {",
- " SimpleComponent create();",
- " Parent set(String s);",
- " }",
- "",
- " @Component.Factory",
- " interface Factory extends Parent {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(String.format(MSGS.twoFactoryMethods(), "create()"))
- .inFile(componentFile)
- .onLineContaining("interface Factory");
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java b/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java
deleted file mode 100644
index 19eabac..0000000
--- a/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java
+++ /dev/null
@@ -1,349 +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;
-
-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;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {ComponentHierarchyValidator}. */
-@RunWith(JUnit4.class)
-public class ComponentHierarchyValidationTest {
- @Test
- public void singletonSubcomponent() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Subcomponent",
- "interface Child {}");
-
- Compilation compilation = daggerCompiler().compile(component, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("conflicting scopes");
- assertThat(compilation).hadErrorContaining("test.Parent also has @Singleton");
-
- Compilation withoutScopeValidation =
- daggerCompiler()
- .withOptions("-Adagger.disableInterComponentScopeValidation=none")
- .compile(component, subcomponent);
- assertThat(withoutScopeValidation).succeeded();
- }
-
- @Test
- public void productionComponents_productionScopeImplicitOnBoth() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- " Object productionScopedObject();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Provides;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.ProductionScope;",
- "",
- "@ProducerModule",
- "class ParentModule {",
- " @Provides @ProductionScope Object parentScopedObject() { return new Object(); }",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent(modules = ChildModule.class)",
- "interface Child {",
- " String productionScopedString();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Provides;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.ProductionScope;",
- "",
- "@ProducerModule",
- "class ChildModule {",
- " @Provides @ProductionScope String childScopedString() { return new String(); }",
- "}");
- Compilation compilation =
- daggerCompiler().compile(component, subcomponent, parentModule, childModule);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void producerModuleRepeated() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = RepeatedProducerModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject repeatedModule =
- JavaFileObjects.forSourceLines(
- "test.RepeatedProducerModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "@ProducerModule",
- "interface RepeatedProducerModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent(modules = RepeatedProducerModule.class)",
- "interface Child {}");
- Compilation compilation = daggerCompiler().compile(component, subcomponent, repeatedModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.Child repeats @ProducerModules:",
- " test.Parent also installs: test.RepeatedProducerModule"))
- .inFile(component)
- .onLineContaining("interface Parent");
- }
-
- @Test
- public void factoryMethodForSubcomponentWithBuilder_isNotAllowed() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module(subcomponents = Sub.class)",
- "class TestModule {",
- "}");
-
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface C {",
- " Sub newSub();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(module, component, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Components may not have factory methods for subcomponents that define a builder.");
- }
-
- @Test
- public void repeatedModulesWithScopes() {
- JavaFileObject testScope =
- JavaFileObjects.forSourceLines(
- "test.TestScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface TestScope {}");
- JavaFileObject moduleWithScopedProvides =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithScopedProvides",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ModuleWithScopedProvides {",
- " @Provides",
- " @TestScope",
- " static Object o() { return new Object(); }",
- "}");
- JavaFileObject moduleWithScopedBinds =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithScopedBinds",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ModuleWithScopedBinds {",
- " @Binds",
- " @TestScope",
- " Object o(String s);",
- "}");
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(",
- " modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
- "interface Child {}");
- Compilation compilation =
- daggerCompiler()
- .compile(testScope, moduleWithScopedProvides, moduleWithScopedBinds, parent, child);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.Child repeats modules with scoped bindings or declarations:",
- " - test.Parent also includes:",
- " - test.ModuleWithScopedProvides with scopes: @test.TestScope",
- " - test.ModuleWithScopedBinds with scopes: @test.TestScope"));
- }
-
- @Test
- public void repeatedModulesWithReusableScope() {
- JavaFileObject moduleWithScopedProvides =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithScopedProvides",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Reusable;",
- "",
- "@Module",
- "class ModuleWithScopedProvides {",
- " @Provides",
- " @Reusable",
- " static Object o() { return new Object(); }",
- "}");
- JavaFileObject moduleWithScopedBinds =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithScopedBinds",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Reusable;",
- "",
- "@Module",
- "interface ModuleWithScopedBinds {",
- " @Binds",
- " @Reusable",
- " Object o(String s);",
- "}");
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(",
- " modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
- "interface Child {}");
- Compilation compilation =
- daggerCompiler()
- .compile(moduleWithScopedProvides, moduleWithScopedBinds, parent, child);
- assertThat(compilation).succeededWithoutWarnings();
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentProcessorTest.java b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
deleted file mode 100644
index 2b79b6f..0000000
--- a/javatests/dagger/internal/codegen/ComponentProcessorTest.java
+++ /dev/null
@@ -1,2769 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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.daggerCompiler;
-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;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Sets;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.MembersInjector;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-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 ComponentProcessorTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ComponentProcessorTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test public void doubleBindingFromResolvedModules() {
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.List;",
- "",
- "@Module",
- "abstract class ParentModule<A> {",
- " @Provides List<A> provideListB(A a) { return null; }",
- "}");
- JavaFileObject child = JavaFileObjects.forSourceLines("test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildNumberModule extends ParentModule<Integer> {",
- " @Provides Integer provideInteger() { return null; }",
- "}");
- JavaFileObject another = JavaFileObjects.forSourceLines("test.AnotherModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.List;",
- "",
- "@Module",
- "class AnotherModule {",
- " @Provides List<Integer> provideListOfInteger() { return null; }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.List;",
- "",
- "@Component(modules = {ChildNumberModule.class, AnotherModule.class})",
- "interface BadComponent {",
- " List<Integer> listOfInteger();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(parent, child, another, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("java.util.List<java.lang.Integer> is bound multiple times");
- assertThat(compilation)
- .hadErrorContaining("@Provides List<Integer> test.ChildNumberModule.provideListB(Integer)");
- assertThat(compilation)
- .hadErrorContaining("@Provides List<Integer> test.AnotherModule.provideListOfInteger()");
- }
-
- @Test public void privateNestedClassWithWarningThatIsAnErrorInComponent() {
- JavaFileObject outerClass = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " @Inject OuterClass(InnerClass innerClass) {}",
- "",
- " private static final class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.BadComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface BadComponent {",
- " OuterClass outerClass();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- compilerMode.javacopts().append("-Adagger.privateMemberValidation=WARNING"))
- .compile(outerClass, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private classes");
- }
-
- @Test public void simpleComponent() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectableType someInjectableType();",
- " Lazy<SomeInjectableType> lazySomeInjectableType();",
- " Provider<SomeInjectableType> someInjectableTypeProvider();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Lazy;",
- "import dagger.internal.DoubleCheck;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<SomeInjectableType> someInjectableTypeProvider;")
- .addLines(
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType();",
- " }",
- "",
- " @Override",
- " public Lazy<SomeInjectableType> lazySomeInjectableType() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return DoubleCheck.lazy(SomeInjectableType_Factory.create());")
- .addLinesIn(
- FAST_INIT_MODE,
- " return DoubleCheck.lazy(someInjectableTypeProvider());")
- .addLines(
- " }",
- "",
- " @Override",
- " public Provider<SomeInjectableType> someInjectableTypeProvider() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return SomeInjectableType_Factory.create();")
- .addLinesIn(
- FAST_INIT_MODE, //
- " Object local = someInjectableTypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " someInjectableTypeProvider = (Provider<SomeInjectableType>) local;",
- " }",
- " return (Provider<SomeInjectableType>) local;")
- .addLines(
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) new SomeInjectableType();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test public void componentWithScope() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectableType someInjectableType();",
- " Lazy<SomeInjectableType> lazySomeInjectableType();",
- " Provider<SomeInjectableType> someInjectableTypeProvider();",
- "}");
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object someInjectableType = new MemoizedSentinel();",
- " private volatile Provider<SomeInjectableType> someInjectableTypeProvider;")
- .addLinesIn(
- DEFAULT_MODE,
- " private Provider<SomeInjectableType> someInjectableTypeProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.someInjectableTypeProvider =",
- " DoubleCheck.provider(SomeInjectableType_Factory.create());",
- " }",
- "")
- .addLines(
- " @Override", //
- " public SomeInjectableType someInjectableType() {")
- .addLinesIn(
- FAST_INIT_MODE,
- " Object local = someInjectableType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = someInjectableType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new SomeInjectableType();",
- " someInjectableType =",
- " DoubleCheck.reentrantCheck(someInjectableType, local);",
- " }",
- " }",
- " }",
- " return (SomeInjectableType) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return someInjectableTypeProvider.get();")
- .addLines(
- " }",
- "",
- " @Override",
- " public Lazy<SomeInjectableType> lazySomeInjectableType() {")
- .addLinesIn(
- DEFAULT_MODE, //
- " return DoubleCheck.lazy(someInjectableTypeProvider);")
- .addLinesIn(
- FAST_INIT_MODE,
- " return DoubleCheck.lazy(someInjectableTypeProvider());")
- .addLines(
- " }",
- "",
- " @Override",
- " public Provider<SomeInjectableType> someInjectableTypeProvider() {")
- .addLinesIn(
- FAST_INIT_MODE, //
- " Object local = someInjectableTypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " someInjectableTypeProvider = (Provider<SomeInjectableType>) local;",
- " }",
- " return (Provider<SomeInjectableType>) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return someInjectableTypeProvider;")
- .addLines( //
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerSimpleComponent.this.someInjectableType();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build();
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void simpleComponentWithNesting() {
- JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "",
- "final class OuterType {",
- " static class A {",
- " @Inject A() {}",
- " }",
- " static class B {",
- " @Inject A a;",
- " }",
- " @Component interface SimpleComponent {",
- " A a();",
- " void inject(B b);",
- " }",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerOuterType_SimpleComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerOuterType_SimpleComponent",
- " implements OuterType.SimpleComponent {",
- " private DaggerOuterType_SimpleComponent() {}",
- "",
- " @Override",
- " public OuterType.A a() {",
- " return new OuterType.A();",
- " }",
- "",
- " @Override",
- " public void inject(OuterType.B b) {",
- " injectB(b);",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private OuterType.B injectB(OuterType.B instance) {",
- " OuterType_B_MembersInjector.injectA(instance, new OuterType.A());",
- " return instance;",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(nestedTypesFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerOuterType_SimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void componentWithModule() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(B b) {}",
- "}");
- JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "interface B {}");
- JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class C {",
- " @Inject C() {}",
- "}");
-
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides B b(C c) { return null; }",
- "}");
-
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " A a();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final TestModule testModule;",
- "",
- " private DaggerTestComponent(TestModule testModuleParam) {",
- " this.testModule = testModuleParam;",
- " }",
- "",
- " private B getB() {",
- " return TestModule_BFactory.b(testModule, new C());",
- " }",
- "",
- " @Override",
- " public A a() {",
- " return new A(getB());",
- " }",
- "",
- " static final class Builder {",
- " private TestModule testModule;",
- "",
- " public Builder testModule(TestModule testModule) {",
- " this.testModule = Preconditions.checkNotNull(testModule);",
- " return this;",
- " }",
- "",
- " public TestComponent build() {",
- " if (testModule == null) {",
- " this.testModule = new TestModule();",
- " }",
- " return new DaggerTestComponent(testModule);",
- " }",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, bFile, cFile, moduleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void componentWithAbstractModule() {
- JavaFileObject aFile =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(B b) {}",
- "}");
- JavaFileObject bFile =
- JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "interface B {}");
- JavaFileObject cFile =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class C {",
- " @Inject C() {}",
- "}");
-
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Provides static B b(C c) { return null; }",
- "}");
-
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " A a();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private B getB() {",
- " return TestModule_BFactory.b(new C());",
- " }",
- "",
- " @Override",
- " public A a() {",
- " return new A(getB());",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, bFile, cFile, moduleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void transitiveModuleDeps() {
- JavaFileObject always = JavaFileObjects.forSourceLines("test.AlwaysIncluded",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class AlwaysIncluded {}");
- JavaFileObject testModule = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = {DepModule.class, AlwaysIncluded.class})",
- "final class TestModule extends ParentTestModule {}");
- JavaFileObject parentTest = JavaFileObjects.forSourceLines("test.ParentTestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = {ParentTestIncluded.class, AlwaysIncluded.class})",
- "class ParentTestModule {}");
- JavaFileObject parentTestIncluded = JavaFileObjects.forSourceLines("test.ParentTestIncluded",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = AlwaysIncluded.class)",
- "final class ParentTestIncluded {}");
- JavaFileObject depModule = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = {RefByDep.class, AlwaysIncluded.class})",
- "final class DepModule extends ParentDepModule {}");
- JavaFileObject refByDep = JavaFileObjects.forSourceLines("test.RefByDep",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = AlwaysIncluded.class)",
- "final class RefByDep extends ParentDepModule {}");
- JavaFileObject parentDep = JavaFileObjects.forSourceLines("test.ParentDepModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = {ParentDepIncluded.class, AlwaysIncluded.class})",
- "class ParentDepModule {}");
- JavaFileObject parentDepIncluded = JavaFileObjects.forSourceLines("test.ParentDepIncluded",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = AlwaysIncluded.class)",
- "final class ParentDepIncluded {}");
-
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- "}");
- // Generated code includes all includes, but excludes the parent modules.
- // The "always" module should only be listed once.
- JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " static final class Builder {",
- "",
- " @Deprecated",
- " public Builder testModule(TestModule testModule) {",
- " Preconditions.checkNotNull(testModule)",
- " return this;",
- " }",
- "",
- " @Deprecated",
- " public Builder parentTestIncluded(ParentTestIncluded parentTestIncluded) {",
- " Preconditions.checkNotNull(parentTestIncluded)",
- " return this;",
- " }",
- "",
- " @Deprecated",
- " public Builder alwaysIncluded(AlwaysIncluded alwaysIncluded) {",
- " Preconditions.checkNotNull(alwaysIncluded)",
- " return this;",
- " }",
- "",
- " @Deprecated",
- " public Builder depModule(DepModule depModule) {",
- " Preconditions.checkNotNull(depModule)",
- " return this;",
- " }",
- "",
- " @Deprecated",
- " public Builder parentDepIncluded(ParentDepIncluded parentDepIncluded) {",
- " Preconditions.checkNotNull(parentDepIncluded)",
- " return this;",
- " }",
- "",
- " @Deprecated",
- " public Builder refByDep(RefByDep refByDep) {",
- " Preconditions.checkNotNull(refByDep)",
- " return this;",
- " }",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent();",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- always,
- testModule,
- parentTest,
- parentTestIncluded,
- depModule,
- refByDep,
- parentDep,
- parentDepIncluded,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void generatedTransitiveModule() {
- JavaFileObject rootModule = JavaFileObjects.forSourceLines("test.RootModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = GeneratedModule.class)",
- "final class RootModule {}");
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = RootModule.class)",
- "interface TestComponent {}");
- assertThat(
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(rootModule, component))
- .failed();
- assertThat(
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class GeneratedModule {}"))
- .compile(rootModule, component))
- .succeeded();
- }
-
- @Test
- public void generatedModuleInSubcomponent() {
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = GeneratedModule.class)",
- "interface ChildComponent {}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent childComponent();",
- "}");
- assertThat(
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(subcomponent, component))
- .failed();
- assertThat(
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class GeneratedModule {}"))
- .compile(subcomponent, component))
- .succeeded();
- }
-
- @Test
- public void subcomponentNotGeneratedIfNotUsedInGraph() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " String notSubcomponent();",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module(subcomponents = Child.class)",
- "class ParentModule {",
- " @Provides static String notSubcomponent() { return new String(); }",
- "}");
-
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "}");
-
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- "",
- " private DaggerParent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static Parent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public String notSubcomponent() {",
- " return ParentModule_NotSubcomponentFactory.notSubcomponent();",
- " }",
- "",
- " static final class Builder {",
- "",
- " private Builder() {}",
- "",
- " @Deprecated",
- " public Builder parentModule(ParentModule parentModule) {",
- " Preconditions.checkNotNull(parentModule);",
- " return this;",
- " }",
- "",
- " public Parent build() {",
- " return new DaggerParent();",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(component, module, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void testDefaultPackage() {
- JavaFileObject aClass = JavaFileObjects.forSourceLines("AClass", "class AClass {}");
- JavaFileObject bClass = JavaFileObjects.forSourceLines("BClass",
- "import javax.inject.Inject;",
- "",
- "class BClass {",
- " @Inject BClass(AClass a) {}",
- "}");
- JavaFileObject aModule = JavaFileObjects.forSourceLines("AModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module class AModule {",
- " @Provides AClass aClass() {",
- " return new AClass();",
- " }",
- "}");
- JavaFileObject component = JavaFileObjects.forSourceLines("SomeComponent",
- "import dagger.Component;",
- "",
- "@Component(modules = AModule.class)",
- "interface SomeComponent {",
- " BClass bClass();",
- "}");
- assertThat(
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aModule, aClass, bClass, component))
- .succeeded();
- }
-
- @Test public void membersInjection() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectedType {",
- " @Inject SomeInjectableType injectedField;",
- " SomeInjectedType() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " void inject(SomeInjectedType instance);",
- " SomeInjectedType injectAndReturn(SomeInjectedType instance);",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " @Override",
- " public void inject(SomeInjectedType instance) {",
- " injectSomeInjectedType(instance);",
- " }",
- "",
- " @Override",
- " public SomeInjectedType injectAndReturn(SomeInjectedType instance) {",
- " return injectSomeInjectedType(instance);",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private SomeInjectedType injectSomeInjectedType(SomeInjectedType instance) {",
- " SomeInjectedType_MembersInjector.injectInjectedField(",
- " instance, new SomeInjectableType());",
- " return instance;",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, injectedTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void componentInjection() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType(SimpleComponent component) {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectableType someInjectableType();",
- " Provider<SimpleComponent> selfProvider();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<SimpleComponent> simpleComponentProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.simpleComponentProvider = InstanceFactory.create((SimpleComponent) this);",
- " }",
- "",
- " @Override",
- " public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType(this)",
- " }",
- "",
- " @Override",
- " public Provider<SimpleComponent> selfProvider() {",
- " return simpleComponentProvider;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void membersInjectionInsideProvision() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject injectedTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectedType {",
- " @Inject SomeInjectableType injectedField;",
- " @Inject SomeInjectedType() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectedType createAndInject();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerSimpleComponent")
- .addLines(
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " @Override",
- " public SomeInjectedType createAndInject() {",
- " return injectSomeInjectedType(",
- " SomeInjectedType_Factory.newInstance());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private SomeInjectedType injectSomeInjectedType(SomeInjectedType instance) {",
- " SomeInjectedType_MembersInjector.injectInjectedField(",
- " instance, new SomeInjectableType());",
- " return instance;",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, injectedTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void componentDependency() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A() {}",
- "}");
- JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class B {",
- " @Inject B(Provider<A> a) {}",
- "}");
- JavaFileObject aComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface AComponent {",
- " A a();",
- "}");
- JavaFileObject bComponentFile = JavaFileObjects.forSourceLines("test.AComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = AComponent.class)",
- "interface BComponent {",
- " B b();",
- "}");
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerBComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerBComponent implements BComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " private Provider<A> aProvider;")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final AComponent aComponent;",
- " private volatile Provider<A> aProvider;",
- "",
- " private DaggerBComponent(AComponent aComponentParam) {",
- " this.aComponent = aComponentParam;",
- " }",
- "",
- " private Provider<A> getAProvider() {",
- " Object local = aProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " aProvider = (Provider<A>) local;",
- " }",
- " return (Provider<A>) local;",
- " }")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"unchecked\")",
- " 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(getAProvider());")
- .addLines(
- " }",
- "",
- " static final class Builder {",
- " private AComponent aComponent;",
- "",
- " public Builder aComponent(AComponent aComponent) {",
- " this.aComponent = Preconditions.checkNotNull(aComponent);",
- " return this;",
- " }",
- "",
- " public BComponent build() {",
- " Preconditions.checkBuilderRequirement(aComponent, AComponent.class);",
- " return new DaggerBComponent(aComponent);",
- " }",
- " }")
- .addLinesIn(
- DEFAULT_MODE,
- " private static class test_AComponent_a implements Provider<A> {",
- " private final AComponent aComponent;",
- " ",
- " test_AComponent_a(AComponent aComponent) {",
- " this.aComponent = aComponent;",
- " }",
- " ",
- " @Override()",
- " public A get() {",
- " return Preconditions.checkNotNull(",
- " aComponent.a(), " + NPE_FROM_COMPONENT_METHOD + ");",
- " }",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T)",
- " Preconditions.checkNotNull(",
- " DaggerBComponent.this.aComponent.a(),",
- " " + NPE_FROM_COMPONENT_METHOD + ");",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build();
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, bFile, aComponentFile, bComponentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerBComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void moduleNameCollision() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "public final class A {}");
- JavaFileObject otherAFile = JavaFileObjects.forSourceLines("other.test.A",
- "package other.test;",
- "",
- "public final class A {}");
-
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "public final class TestModule {",
- " @Provides A a() { return null; }",
- "}");
- JavaFileObject otherModuleFile = JavaFileObjects.forSourceLines("other.test.TestModule",
- "package other.test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "public final class TestModule {",
- " @Provides A a() { return null; }",
- "}");
-
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {TestModule.class, other.test.TestModule.class})",
- "interface TestComponent {",
- " A a();",
- " other.test.A otherA();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final TestModule testModule;",
- " private final other.test.TestModule testModule2;",
- "",
- " private DaggerTestComponent(",
- " TestModule testModuleParam,",
- " other.test.TestModule testModule2Param) {",
- " this.testModule = testModuleParam;",
- " this.testModule2 = testModule2Param;",
- " }",
- "",
- " @Override",
- " public A a() {",
- " return TestModule_AFactory.a(testModule);",
- " }",
- "",
- " @Override",
- " public other.test.A otherA() {",
- " return other.test.TestModule_AFactory.a(testModule2);",
- " }",
- "",
- " static final class Builder {",
- " private TestModule testModule;",
- " private other.test.TestModule testModule2;",
- "",
- " public Builder testModule(TestModule testModule) {",
- " this.testModule = Preconditions.checkNotNull(testModule);",
- " return this;",
- " }",
- "",
- " public Builder testModule(other.test.TestModule testModule) {",
- " this.testModule2 = Preconditions.checkNotNull(testModule);",
- " return this;",
- " }",
- "",
- " public TestComponent build() {",
- " if (testModule == null) {",
- " this.testModule = new TestModule();",
- " }",
- " if (testModule2 == null) {",
- " this.testModule2 = new other.test.TestModule();",
- " }",
- " return new DaggerTestComponent(testModule, testModule2);",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, otherAFile, moduleFile, otherModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void ignoresDependencyMethodsFromObject() {
- JavaFileObject injectedTypeFile =
- JavaFileObjects.forSourceLines(
- "test.InjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class InjectedType {",
- " @Inject InjectedType(",
- " String stringInjection,",
- " int intInjection,",
- " AComponent aComponent,",
- " Class<AComponent> aClass) {}",
- "}");
- JavaFileObject aComponentFile =
- JavaFileObjects.forSourceLines(
- "test.AComponent",
- "package test;",
- "",
- "class AComponent {",
- " String someStringInjection() {",
- " return \"injectedString\";",
- " }",
- "",
- " int someIntInjection() {",
- " return 123;",
- " }",
- "",
- " Class<AComponent> someClassInjection() {",
- " return AComponent.class;",
- " }",
- "",
- " @Override",
- " public String toString() {",
- " return null;",
- " }",
- "",
- " @Override",
- " public int hashCode() {",
- " return 456;",
- " }",
- "",
- " @Override",
- " public AComponent clone() {",
- " return null;",
- " }",
- "}");
- JavaFileObject bComponentFile =
- JavaFileObjects.forSourceLines(
- "test.AComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = AComponent.class)",
- "interface BComponent {",
- " InjectedType injectedType();",
- "}");
-
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerBComponent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerBComponent implements BComponent {",
- " private final AComponent aComponent;",
- "",
- " private DaggerBComponent(AComponent aComponentParam) {",
- " this.aComponent = aComponentParam;",
- " }",
- "",
- " @Override",
- " public InjectedType injectedType() {",
- " return new InjectedType(",
- " Preconditions.checkNotNull(",
- " aComponent.someStringInjection(),",
- " \"Cannot return null from a non-@Nullable component method\"),",
- " aComponent.someIntInjection(),",
- " aComponent,",
- " Preconditions.checkNotNull(",
- " aComponent.someClassInjection(),",
- " \"Cannot return null from a non-@Nullable component method\"));",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectedTypeFile, aComponentFile, bComponentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerBComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void resolutionOrder() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(B b) {}",
- "}");
- JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class B {",
- " @Inject B(C c) {}",
- "}");
- JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class C {",
- " @Inject C() {}",
- "}");
- JavaFileObject xFile = JavaFileObjects.forSourceLines("test.X",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class X {",
- " @Inject X(C c) {}",
- "}");
-
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface TestComponent {",
- " A a();",
- " C c();",
- " X x();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private B getB() {",
- " return new B(new C());",
- " }",
- "",
- " @Override",
- " public A a() {",
- " return new A(getB());",
- " }",
- "",
- " @Override",
- " public C c() {",
- " return new C();",
- " }",
- "",
- " @Override",
- " public X x() {",
- " return new X(new C());",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, bFile, cFile, xFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void simpleComponent_redundantComponentMethod() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject componentSupertypeAFile = JavaFileObjects.forSourceLines("test.SupertypeA",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SupertypeA {",
- " SomeInjectableType someInjectableType();",
- "}");
- JavaFileObject componentSupertypeBFile = JavaFileObjects.forSourceLines("test.SupertypeB",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SupertypeB {",
- " SomeInjectableType someInjectableType();",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent extends SupertypeA, SupertypeB {",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- injectableTypeFile,
- componentSupertypeAFile,
- componentSupertypeBFile,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test public void simpleComponent_inheritedComponentMethodDep() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType() {}",
- "}");
- JavaFileObject componentSupertype = JavaFileObjects.forSourceLines("test.Supertype",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Supertype {",
- " SomeInjectableType someInjectableType();",
- "}");
- JavaFileObject depComponentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent extends Supertype {",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " @Override",
- " public SomeInjectableType someInjectableType() {",
- " return new SomeInjectableType();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, componentSupertype, depComponentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void wildcardGenericsRequiresAtProvides() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A() {}",
- "}");
- JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class B<T> {",
- " @Inject B(T t) {}",
- "}");
- JavaFileObject cFile = JavaFileObjects.forSourceLines("test.C",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class C {",
- " @Inject C(B<? extends A> bA) {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " C c();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(aFile, bFile, cFile, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.B<? extends test.A> cannot be provided without an @Provides-annotated method");
- }
-
- // https://github.com/google/dagger/issues/630
- @Test
- public void arrayKeyRequiresAtProvides() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " String[] array();",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("String[] cannot be provided without an @Provides-annotated method");
- }
-
- @Test
- public void componentImplicitlyDependsOnGeneratedType() {
- JavaFileObject injectableTypeFile = JavaFileObjects.forSourceLines("test.SomeInjectableType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SomeInjectableType {",
- " @Inject SomeInjectableType(GeneratedType generatedType) {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " SomeInjectableType someInjectableType();",
- "}");
- Compilation compilation =
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class GeneratedType {",
- " @Inject GeneratedType() {}",
- "}"))
- .withOptions(compilerMode.javacopts())
- .compile(injectableTypeFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation).generatedSourceFile("test.DaggerSimpleComponent");
- }
-
- @Test
- public void componentSupertypeDependsOnGeneratedType() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent extends SimpleComponentInterface {}");
- JavaFileObject interfaceFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponentInterface",
- "package test;",
- "",
- "interface SimpleComponentInterface {",
- " GeneratedType generatedType();",
- "}");
- Compilation compilation =
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class GeneratedType {",
- " @Inject GeneratedType() {}",
- "}"))
- .withOptions(compilerMode.javacopts())
- .compile(componentFile, interfaceFile);
- assertThat(compilation).succeeded();
- assertThat(compilation).generatedSourceFile("test.DaggerSimpleComponent");
- }
-
- /**
- * We warn when generating a {@link MembersInjector} for a type post-hoc (i.e., if Dagger wasn't
- * invoked when compiling the type). But Dagger only generates {@link MembersInjector}s for types
- * with {@link Inject @Inject} constructors if they have any injection sites, and it only
- * generates them for types without {@link Inject @Inject} constructors if they have local
- * (non-inherited) injection sites. So make sure we warn in only those cases where running the
- * Dagger processor actually generates a {@link MembersInjector}.
- */
- @Test
- public void unprocessedMembersInjectorNotes() {
- Compilation compilation =
- javac()
- .withOptions(
- compilerMode
- .javacopts()
- .append(
- "-Xlint:-processing",
- "-Adagger.warnIfInjectionFactoryNotGeneratedUpstream=enabled"))
- .withProcessors(
- new ElementFilteringComponentProcessor(
- Predicates.not(
- element ->
- MoreElements.getPackage(element)
- .getQualifiedName()
- .contentEquals("test.inject"))))
- .compile(
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(test.inject.NoInjectMemberNoConstructor object);",
- " void inject(test.inject.NoInjectMemberWithConstructor object);",
- " void inject(test.inject.LocalInjectMemberNoConstructor object);",
- " void inject(test.inject.LocalInjectMemberWithConstructor object);",
- " void inject(test.inject.ParentInjectMemberNoConstructor object);",
- " void inject(test.inject.ParentInjectMemberWithConstructor object);",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class TestModule {",
- " @Provides static Object object() {",
- " return \"object\";",
- " }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.inject.NoInjectMemberNoConstructor",
- "package test.inject;",
- "",
- "public class NoInjectMemberNoConstructor {",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.inject.NoInjectMemberWithConstructor",
- "package test.inject;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class NoInjectMemberWithConstructor {",
- " @Inject NoInjectMemberWithConstructor() {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.inject.LocalInjectMemberNoConstructor",
- "package test.inject;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class LocalInjectMemberNoConstructor {",
- " @Inject Object object;",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.inject.LocalInjectMemberWithConstructor",
- "package test.inject;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class LocalInjectMemberWithConstructor {",
- " @Inject LocalInjectMemberWithConstructor() {}",
- " @Inject Object object;",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.inject.ParentInjectMemberNoConstructor",
- "package test.inject;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class ParentInjectMemberNoConstructor",
- " extends LocalInjectMemberNoConstructor {}"),
- JavaFileObjects.forSourceLines(
- "test.inject.ParentInjectMemberWithConstructor",
- "package test.inject;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class ParentInjectMemberWithConstructor",
- " extends LocalInjectMemberNoConstructor {",
- " @Inject ParentInjectMemberWithConstructor() {}",
- "}"));
-
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .hadNoteContaining(
- "Generating a MembersInjector for "
- + "test.inject.LocalInjectMemberNoConstructor. "
- + "Prefer to run the dagger processor over that class instead.");
- assertThat(compilation)
- .hadNoteContaining(
- "Generating a MembersInjector for "
- + "test.inject.LocalInjectMemberWithConstructor. "
- + "Prefer to run the dagger processor over that class instead.");
- assertThat(compilation)
- .hadNoteContaining(
- "Generating a MembersInjector for "
- + "test.inject.ParentInjectMemberWithConstructor. "
- + "Prefer to run the dagger processor over that class instead.");
- assertThat(compilation).hadNoteCount(3);
- }
-
- @Test
- public void scopeAnnotationOnInjectConstructorNotValid() {
- JavaFileObject aScope =
- JavaFileObjects.forSourceLines(
- "test.AScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface AScope {}");
- JavaFileObject aClass =
- JavaFileObjects.forSourceLines(
- "test.AClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class AClass {",
- " @Inject @AScope AClass() {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(aScope, aClass);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Scope annotations are not allowed on @Inject constructors")
- .inFile(aClass)
- .onLine(6);
- }
-
- @Test
- public void unusedSubcomponents_dontResolveExtraBindingsInParentComponents() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(subcomponents = Pruned.class)",
- "class TestModule {}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = TestModule.class)",
- "interface Parent {}");
-
- JavaFileObject prunedSubcomponent =
- JavaFileObjects.forSourceLines(
- "test.Pruned",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Pruned {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Pruned build();",
- " }",
- "",
- " Foo foo();",
- "}");
- JavaFileObject generated =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private DaggerParent() {",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static Parent create() {",
- " return new Builder().build();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " @Deprecated",
- " public Builder testModule(TestModule testModule) {",
- " Preconditions.checkNotNull(testModule);",
- " return this;",
- " }",
- "",
- " public Parent build() {",
- " return new DaggerParent();",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(foo, module, component, prunedSubcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .hasSourceEquivalentTo(generated);
- }
-
- @Test
- public void bindsToDuplicateBinding_bindsKeyIsNotDuplicated() {
- JavaFileObject firstModule =
- JavaFileObjects.forSourceLines(
- "test.FirstModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class FirstModule {",
- " @Provides static String first() { return \"first\"; }",
- "}");
- JavaFileObject secondModule =
- JavaFileObjects.forSourceLines(
- "test.SecondModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class SecondModule {",
- " @Provides static String second() { return \"second\"; }",
- "}");
- JavaFileObject bindsModule =
- JavaFileObjects.forSourceLines(
- "test.BindsModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class BindsModule {",
- " @Binds abstract Object bindToDuplicateBinding(String duplicate);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = {FirstModule.class, SecondModule.class, BindsModule.class})",
- "interface TestComponent {",
- " Object notDuplicated();",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(firstModule, secondModule, bindsModule, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("java.lang.String is bound multiple times")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void nullIncorrectlyReturnedFromNonNullableInlinedProvider() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Provides static String nonNullableString() { return \"string\"; }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.InjectsMember",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class InjectsMember {",
- " @Inject String member;",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " String nonNullableString();",
- " void inject(InjectsMember member);",
- "}"));
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.TestModule_NonNullableStringFactory")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.TestModule_NonNullableStringFactory",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_NonNullableStringFactory",
- " implements Factory<String> {",
- " @Override",
- " public String get() {",
- " return nonNullableString();",
- " }",
- "",
- " public static String nonNullableString() {",
- " return Preconditions.checkNotNull(",
- " TestModule.nonNullableString(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}"));
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public String nonNullableString() {",
- " return TestModule_NonNullableStringFactory.nonNullableString());",
- " }",
- "",
- " @Override",
- " public void inject(InjectsMember member) {",
- " injectInjectsMember(member);",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private InjectsMember injectInjectsMember(InjectsMember instance) {",
- " InjectsMember_MembersInjector.injectMember(instance,",
- " TestModule_NonNullableStringFactory.nonNullableString());",
- " return instance;",
- " }",
- "}")
- .build();
-
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void nullCheckingIgnoredWhenProviderReturnsPrimitive() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Provides static int primitiveInteger() { return 1; }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.InjectsMember",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class InjectsMember {",
- " @Inject Integer member;",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Integer nonNullableInteger();",
- " void inject(InjectsMember member);",
- "}"));
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.TestModule_PrimitiveIntegerFactory")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.TestModule_PrimitiveIntegerFactory",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_PrimitiveIntegerFactory",
- " implements Factory<Integer> {",
- "",
- " @Override",
- " public Integer get() {",
- " return primitiveInteger();",
- " }",
- "",
- " public static int primitiveInteger() {",
- " return TestModule.primitiveInteger();",
- " }",
- "}"));
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Integer nonNullableInteger() {",
- " return TestModule.primitiveInteger();",
- " }",
- "",
- " @Override",
- " public void inject(InjectsMember member) {",
- " injectInjectsMember(member);",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private InjectsMember injectInjectsMember(InjectsMember instance) {",
- " InjectsMember_MembersInjector.injectMember(",
- " instance, TestModule.primitiveInteger());",
- " return instance;",
- " }",
- "}")
- .build();
-
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void privateMethodUsedOnlyInChildDoesNotUseQualifiedThis() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules=TestModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject testModule =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Provides @Singleton static Number number() {",
- " return 3;",
- " }",
- "",
- " @Provides static String string(Number number) {",
- " return number.toString();",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child {",
- " String string();",
- "}");
-
- JavaFileObject expectedPattern =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private String getString() {",
- " return TestModule_StringFactory.string(numberProvider.get());",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, testModule, child);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(expectedPattern);
- }
-
- @Test
- public void componentMethodInChildCallsComponentMethodInParent() {
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " String string();",
- "}");
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules=TestModule.class)",
- "interface Parent extends Supertype {",
- " Child child();",
- "}");
- JavaFileObject testModule =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Provides @Singleton static Number number() {",
- " return 3;",
- " }",
- "",
- " @Provides static String string(Number number) {",
- " return number.toString();",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child extends Supertype {}");
-
- JavaFileObject expectedPattern =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private final class ChildImpl implements Child {",
- " @Override",
- " public String string() {",
- " return DaggerParent.this.string();",
- " }",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(supertype, parent, testModule, child);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(expectedPattern);
- }
-
- @Test
- public void justInTimeAtInjectConstructor_hasGeneratedQualifier() {
- JavaFileObject injected =
- JavaFileObjects.forSourceLines(
- "test.Injected",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Injected {",
- " @Inject Injected(@GeneratedQualifier String string) {}",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String unqualified() {",
- " return new String();",
- " }",
- "",
- " @Provides",
- " @GeneratedQualifier",
- " static String qualified() {",
- " return new String();",
- " }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Injected injected();",
- "}");
-
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Injected injected() {",
- // Ensure that the qualified @Provides method is used. It's also probably more likely
- // that if the qualifier type hasn't been generated, a duplicate binding error will be
- // reported, since the annotation won't be recognized as a qualifier and instead as an
- // ordinary annotation.
- " return new Injected(TestModule_QualifiedFactory.qualified());",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedQualifier",
- "package test;",
- "",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "import java.lang.annotation.Retention;",
- "import javax.inject.Qualifier;",
- "",
- "@Retention(RUNTIME)",
- "@Qualifier",
- "@interface GeneratedQualifier {}"))
- .compile(injected, module, component);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void moduleHasGeneratedQualifier() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String unqualified() {",
- " return new String();",
- " }",
- "",
- " @Provides",
- " @GeneratedQualifier",
- " static String qualified() {",
- " return new String();",
- " }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " String unqualified();",
- "}");
-
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public String unqualified() {",
- // Ensure that the unqualified @Provides method is used. It's also probably more likely
- // if the qualifier hasn't been generated, a duplicate binding exception will be thrown
- // since the annotation won't be considered a qualifier
- " return TestModule_UnqualifiedFactory.unqualified();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedQualifier",
- "package test;",
- "",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "import java.lang.annotation.Retention;",
- "import javax.inject.Qualifier;",
- "",
- "@Retention(RUNTIME)",
- "@Qualifier",
- "@interface GeneratedQualifier {}"))
- .compile(module, component);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void publicComponentType() {
- JavaFileObject publicComponent =
- JavaFileObjects.forSourceLines(
- "test.PublicComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "public interface PublicComponent {}");
- Compilation compilation = daggerCompiler().compile(publicComponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerPublicComponent")
- .hasSourceEquivalentTo(
- JavaFileObjects.forSourceLines(
- "test.DaggerPublicComponent",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerPublicComponent implements PublicComponent {",
- " private DaggerPublicComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static PublicComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {}",
- "",
- " public PublicComponent build() {",
- " return new DaggerPublicComponent();",
- " }",
- " }",
- "}"));
- }
-
- /**
- * A {@link ComponentProcessor} that excludes elements using a {@link Predicate}.
- */
- private static final class ElementFilteringComponentProcessor extends AbstractProcessor {
- private final ComponentProcessor componentProcessor = new ComponentProcessor();
- private final Predicate<? super Element> filter;
-
- /**
- * Creates a {@link ComponentProcessor} that only processes elements that match {@code filter}.
- */
- public ElementFilteringComponentProcessor(Predicate<? super Element> filter) {
- this.filter = filter;
- }
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnv) {
- super.init(processingEnv);
- componentProcessor.init(processingEnv);
- }
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return componentProcessor.getSupportedAnnotationTypes();
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return componentProcessor.getSupportedSourceVersion();
- }
-
- @Override
- public Set<String> getSupportedOptions() {
- return componentProcessor.getSupportedOptions();
- }
-
- @Override
- public boolean process(
- Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
- return componentProcessor.process(
- annotations,
- new RoundEnvironment() {
- @Override
- public boolean processingOver() {
- return roundEnv.processingOver();
- }
-
- @Override
- public Set<? extends Element> getRootElements() {
- return Sets.filter(roundEnv.getRootElements(), filter);
- }
-
- @Override
- public Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a) {
- return Sets.filter(roundEnv.getElementsAnnotatedWith(a), filter);
- }
-
- @Override
- public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) {
- return Sets.filter(roundEnv.getElementsAnnotatedWith(a), filter);
- }
-
- @Override
- public boolean errorRaised() {
- return roundEnv.errorRaised();
- }
- });
- }
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
deleted file mode 100644
index 85e2d7b..0000000
--- a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
+++ /dev/null
@@ -1,436 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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;
-import java.util.Collection;
-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 ComponentRequirementFieldTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ComponentRequirementFieldTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void bindsInstance() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "import java.util.List;",
- "",
- "@Component",
- "interface TestComponent {",
- " int i();",
- " List<String> list();",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder i(int i);",
- " @BindsInstance Builder list(List<String> list);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final Integer i;",
- " private final List<String> list;",
- "",
- " private DaggerTestComponent(Integer iParam, List<String> listParam) {",
- " this.i = iParam;",
- " this.list = listParam;",
- " }",
- "",
- " @Override",
- " public int i() {",
- " return i;",
- " }",
- "",
- " @Override",
- " public List<String> list() {",
- " return list;",
- " }",
- "",
- " private static final class Builder implements TestComponent.Builder {",
- " private Integer i;",
- " private List<String> list;",
- "",
- " @Override",
- " public Builder i(int i) {",
- " this.i = Preconditions.checkNotNull(i);",
- " return this;",
- " }",
- "",
- " @Override",
- " public Builder list(List<String> list) {",
- " this.list = Preconditions.checkNotNull(list);",
- " return this;",
- " }",
- "",
- " @Override",
- " public TestComponent build() {",
- " Preconditions.checkBuilderRequirement(i, Integer.class);",
- " Preconditions.checkBuilderRequirement(list, List.class);",
- " return new DaggerTestComponent(i, list);",
- " }",
- " }",
- "}"));
- }
-
- @Test
- public void instanceModuleMethod() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides int i() { return 0; }",
- "}");
- JavaFileObject otherPackageModule =
- JavaFileObjects.forSourceLines(
- "other.OtherPackageModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "public class OtherPackageModule {",
- " @Provides long l() { return 0L; }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import other.OtherPackageModule;",
- "",
- "@Component(modules = {ParentModule.class, OtherPackageModule.class})",
- "interface TestComponent {",
- " int i();",
- " long l();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, otherPackageModule, component);
- assertThat(compilation).succeeded();
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import other.OtherPackageModule;",
- "import other.OtherPackageModule_LFactory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final ParentModule parentModule;",
- " private final OtherPackageModule otherPackageModule;",
- "",
- " @Override",
- " public int i() {",
- " return parentModule.i();",
- " }",
- "",
- " @Override",
- " public long l() {",
- " return OtherPackageModule_LFactory.l(otherPackageModule);",
- " }",
- "}");
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void componentInstances() {
- JavaFileObject dependency =
- JavaFileObjects.forSourceLines(
- "test.Dep",
- "package test;",
- "",
- "interface Dep {",
- " String string();",
- " Object object();",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = Dep.class)",
- "interface TestComponent {",
- " TestComponent self();",
- " TestSubcomponent subcomponent();",
- "",
- " Dep dep();",
- " String methodOnDep();",
- " Object otherMethodOnDep();",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface TestSubcomponent {",
- " TestComponent parent();",
- " Dep depFromSubcomponent();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(dependency, component, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final Dep dep;",
- "",
- " private DaggerTestComponent(Dep depParam) {",
- " this.dep = depParam;",
- " }",
- "",
- " @Override",
- " public TestComponent self() {",
- " return this;",
- " }",
- "",
- " @Override",
- " public Dep dep() {",
- " return dep;",
- " }",
- "",
- " @Override",
- " public String methodOnDep() {",
- " return Preconditions.checkNotNull(",
- " dep.string(), " + NPE_FROM_COMPONENT_METHOD + " );",
- " }",
- "",
- " @Override",
- " public Object otherMethodOnDep() {",
- " return Preconditions.checkNotNull(",
- " dep.object(), " + NPE_FROM_COMPONENT_METHOD + " );",
- " }",
- "",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
- " @Override",
- " public TestComponent parent() {",
- " return DaggerTestComponent.this;",
- " }",
- "",
- " @Override",
- " public Dep depFromSubcomponent() {",
- " return DaggerTestComponent.this.dep;",
- " }",
- " }",
- "}"));
- }
-
- @Test
- public void componentRequirementNeededInFactoryCreationOfSubcomponent() {
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.Provides;",
- "import java.util.Set;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides",
- // intentionally non-static. this needs to require the module when the subcompnent
- // adds to the Set binding
- " Object reliesOnMultibinding(Set<Object> set) { return set; }",
- "",
- " @Provides @IntoSet static Object contribution() { return new Object(); }",
- "}");
-
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildModule {",
- " @Provides @IntoSet static Object contribution() { return new Object(); }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface TestComponent {",
- " Provider<Object> dependsOnMultibinding();",
- " TestSubcomponent subcomponent();",
- "}");
-
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface TestSubcomponent {",
- " Provider<Object> dependsOnMultibinding();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final ParentModule parentModule;",
- "",
- " private DaggerTestComponent(ParentModule parentModuleParam) {",
- " this.parentModule = parentModuleParam;",
- " }",
- "",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
- " private Set<Object> getSetOfObject() {",
- " return ImmutableSet.<Object>of(",
- " ParentModule_ContributionFactory.contribution(),",
- " ChildModule_ContributionFactory.contribution());",
- " }",
- "",
- " private Object getObject() {",
- " return ParentModule_ReliesOnMultibindingFactory.reliesOnMultibinding(",
- " DaggerTestComponent.this.parentModule, getSetOfObject());",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final ParentModule parentModule;",
- "",
- " private DaggerTestComponent(ParentModule parentModuleParam) {",
- " this.parentModule = parentModuleParam;",
- " initialize(parentModuleParam);",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final ParentModule parentModuleParam) {",
- " this.setOfObjectProvider =",
- " SetFactory.<Object>builder(1, 0)",
- " .addProvider(ParentModule_ContributionFactory.create())",
- " .build();",
- " this.reliesOnMultibindingProvider =",
- " ParentModule_ReliesOnMultibindingFactory.create(",
- " parentModuleParam, setOfObjectProvider);",
- " }",
- "",
- " private final class TestSubcomponentImpl implements TestSubcomponent {",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.setOfObjectProvider =",
- " SetFactory.<Object>builder(2, 0)",
- " .addProvider(ParentModule_ContributionFactory.create())",
- " .addProvider(ChildModule_ContributionFactory.create())",
- " .build();",
- " this.reliesOnMultibindingProvider =",
- " ParentModule_ReliesOnMultibindingFactory.create(",
- " DaggerTestComponent.this.parentModule, setOfObjectProvider);",
- " }",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(parentModule, childModule, component, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentValidationTest.java b/javatests/dagger/internal/codegen/ComponentValidationTest.java
deleted file mode 100644
index 169a318..0000000
--- a/javatests/dagger/internal/codegen/ComponentValidationTest.java
+++ /dev/null
@@ -1,356 +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;
-
-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;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ComponentValidationTest {
- @Test
- public void componentOnConcreteClass() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "final class NotAComponent {}");
- Compilation compilation = daggerCompiler().compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void componentOnEnum() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "enum NotAComponent {",
- " INSTANCE",
- "}");
- Compilation compilation = daggerCompiler().compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void componentOnAnnotation() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "@interface NotAComponent {}");
- Compilation compilation = daggerCompiler().compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void nonModuleModule() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = Object.class)",
- "interface NotAComponent {}");
- Compilation compilation = daggerCompiler().compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("is not annotated with @Module");
- }
-
- @Test
- public void componentWithInvalidModule() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.BadModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class BadModule {",
- " @Binds abstract Object noParameters();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.BadComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = BadModule.class)",
- "interface BadComponent {",
- " Object object();",
- "}");
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation)
- .hadErrorContaining("test.BadModule has errors")
- .inFile(component)
- .onLine(5);
- }
-
- @Test
- public void attemptToInjectWildcardGenerics() {
- JavaFileObject testComponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface TestComponent {",
- " Lazy<? extends Number> wildcardNumberLazy();",
- " Provider<? super Number> wildcardNumberProvider();",
- "}");
- Compilation compilation = daggerCompiler().compile(testComponent);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("wildcard type").inFile(testComponent).onLine(9);
- assertThat(compilation).hadErrorContaining("wildcard type").inFile(testComponent).onLine(10);
- }
-
- @Test
- public void invalidComponentDependencies() {
- JavaFileObject testComponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = int.class)",
- "interface TestComponent {}");
- Compilation compilation = daggerCompiler().compile(testComponent);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("int is not a valid component dependency type");
- }
-
- @Test
- public void invalidComponentModules() {
- JavaFileObject testComponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = int.class)",
- "interface TestComponent {}");
- Compilation compilation = daggerCompiler().compile(testComponent);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("int is not a valid module type");
- }
-
- @Test
- public void moduleInDependencies() {
- JavaFileObject testModule =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String s() { return null; }",
- "}");
- JavaFileObject testComponent =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = TestModule.class)",
- "interface TestComponent {}");
- Compilation compilation = daggerCompiler().compile(testModule, testComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.TestModule is a module, which cannot be a component dependency");
- }
-
- @Test
- public void componentDependencyMustNotCycle_Direct() {
- JavaFileObject shortLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentShort",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = ComponentShort.class)",
- "interface ComponentShort {",
- "}");
-
- Compilation compilation = daggerCompiler().compile(shortLifetime);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentShort contains a cycle in its component dependencies:",
- " test.ComponentShort"));
- }
-
- @Test
- public void componentDependencyMustNotCycle_Indirect() {
- JavaFileObject longLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentLong",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = ComponentMedium.class)",
- "interface ComponentLong {",
- "}");
- JavaFileObject mediumLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentMedium",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = ComponentLong.class)",
- "interface ComponentMedium {",
- "}");
- JavaFileObject shortLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentShort",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = ComponentMedium.class)",
- "interface ComponentShort {",
- "}");
-
- Compilation compilation = daggerCompiler().compile(longLifetime, mediumLifetime, shortLifetime);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentLong contains a cycle in its component dependencies:",
- " test.ComponentLong",
- " test.ComponentMedium",
- " test.ComponentLong"))
- .inFile(longLifetime);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentMedium contains a cycle in its component dependencies:",
- " test.ComponentMedium",
- " test.ComponentLong",
- " test.ComponentMedium"))
- .inFile(mediumLifetime);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentShort contains a cycle in its component dependencies:",
- " test.ComponentMedium",
- " test.ComponentLong",
- " test.ComponentMedium",
- " test.ComponentShort"))
- .inFile(shortLifetime);
- }
-
- @Test
- public void abstractModuleWithInstanceMethod() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Provides int i() { return 1; }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " int i();",
- "}");
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("TestModule is abstract and has instance @Provides methods")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void abstractModuleWithInstanceMethod_subclassedIsAllowed() {
- JavaFileObject abstractModule =
- JavaFileObjects.forSourceLines(
- "test.AbstractModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class AbstractModule {",
- " @Provides int i() { return 1; }",
- "}");
- JavaFileObject subclassedModule =
- JavaFileObjects.forSourceLines(
- "test.SubclassedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "class SubclassedModule extends AbstractModule {}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = SubclassedModule.class)",
- "interface TestComponent {",
- " int i();",
- "}");
- Compilation compilation = daggerCompiler().compile(abstractModule, subclassedModule, component);
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/internal/codegen/ConflictingEntryPointsTest.java b/javatests/dagger/internal/codegen/ConflictingEntryPointsTest.java
deleted file mode 100644
index 7ffd922..0000000
--- a/javatests/dagger/internal/codegen/ConflictingEntryPointsTest.java
+++ /dev/null
@@ -1,262 +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 dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.message;
-
-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 ConflictingEntryPointsTest {
-
- @Test
- public void covariantType() {
- JavaFileObject base1 =
- JavaFileObjects.forSourceLines(
- "test.Base1", //
- "package test;",
- "",
- "interface Base1 {",
- " Long foo();",
- "}");
- JavaFileObject base2 =
- JavaFileObjects.forSourceLines(
- "test.Base2", //
- "package test;",
- "",
- "interface Base2 {",
- " Number foo();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent extends Base1, Base2 {",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(Long foo);",
- " @BindsInstance Builder foo(Number foo);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(base1, base2, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "conflicting entry point declarations:",
- " Long test.Base1.foo()",
- " Number test.Base2.foo()"))
- .inFile(component)
- .onLineContaining("interface TestComponent ");
- }
-
- @Test
- public void covariantTypeFromGenericSupertypes() {
- JavaFileObject base1 =
- JavaFileObjects.forSourceLines(
- "test.Base1", //
- "package test;",
- "",
- "interface Base1<T> {",
- " T foo();",
- "}");
- JavaFileObject base2 =
- JavaFileObjects.forSourceLines(
- "test.Base2", //
- "package test;",
- "",
- "interface Base2<T> {",
- " T foo();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent extends Base1<Long>, Base2<Number> {",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(Long foo);",
- " @BindsInstance Builder foo(Number foo);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(base1, base2, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "conflicting entry point declarations:",
- " Long test.Base1.foo()",
- " Number test.Base2.foo()"))
- .inFile(component)
- .onLineContaining("interface TestComponent ");
- }
-
- @Test
- public void differentQualifier() {
- JavaFileObject base1 =
- JavaFileObjects.forSourceLines(
- "test.Base1", //
- "package test;",
- "",
- "interface Base1 {",
- " Object foo();",
- "}");
- JavaFileObject base2 =
- JavaFileObjects.forSourceLines(
- "test.Base2", //
- "package test;",
- "",
- "import javax.inject.Named;",
- "",
- "interface Base2 {",
- " @Named(\"foo\") Object foo();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "import javax.inject.Named;",
- "",
- "@Component",
- "interface TestComponent extends Base1, Base2 {",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(Object foo);",
- " @BindsInstance Builder namedFoo(@Named(\"foo\") Object foo);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(base1, base2, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "conflicting entry point declarations:",
- " Object test.Base1.foo()",
- " @Named(\"foo\") Object test.Base2.foo()"))
- .inFile(component)
- .onLineContaining("interface TestComponent ");
- }
-
- @Test
- public void sameKey() {
- JavaFileObject base1 =
- JavaFileObjects.forSourceLines(
- "test.Base1", //
- "package test;",
- "",
- "interface Base1 {",
- " Object foo();",
- "}");
- JavaFileObject base2 =
- JavaFileObjects.forSourceLines(
- "test.Base2", //
- "package test;",
- "",
- "interface Base2 {",
- " Object foo();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent extends Base1, Base2 {",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(Object foo);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(base1, base2, component);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void sameQualifiedKey() {
- JavaFileObject base1 =
- JavaFileObjects.forSourceLines(
- "test.Base1", //
- "package test;",
- "",
- "import javax.inject.Named;",
- "",
- "interface Base1 {",
- " @Named(\"foo\") Object foo();",
- "}");
- JavaFileObject base2 =
- JavaFileObjects.forSourceLines(
- "test.Base2", //
- "package test;",
- "",
- "import javax.inject.Named;",
- "",
- "interface Base2 {",
- " @Named(\"foo\") Object foo();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Component;",
- "import javax.inject.Named;",
- "",
- "@Component",
- "interface TestComponent extends Base1, Base2 {",
- "",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(@Named(\"foo\") Object foo);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(base1, base2, component);
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java b/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java
deleted file mode 100644
index 1fcf7bc..0000000
--- a/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java
+++ /dev/null
@@ -1,184 +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;
-
-import static com.google.common.truth.Truth.assertAbout;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.truth.FailureMetadata;
-import com.google.common.truth.Subject;
-import com.google.common.truth.Truth;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.List;
-import javax.tools.JavaFileObject;
-
-/** A {@link Truth} subject for testing Dagger module methods. */
-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> {
-
- /** Starts a clause testing a Dagger {@link Module @Module} method. */
- static DaggerModuleMethodSubject assertThatModuleMethod(String method) {
- return assertAbout(daggerModuleMethod())
- .that(method)
- .withDeclaration("@Module abstract class %s { %s }");
- }
-
- /** Starts a clause testing a Dagger {@link ProducerModule @ProducerModule} method. */
- static DaggerModuleMethodSubject assertThatProductionModuleMethod(String method) {
- return assertAbout(daggerModuleMethod())
- .that(method)
- .withDeclaration("@ProducerModule abstract class %s { %s }");
- }
-
- /** Starts a clause testing a method in an unannotated class. */
- static DaggerModuleMethodSubject assertThatMethodInUnannotatedClass(String method) {
- return assertAbout(daggerModuleMethod())
- .that(method)
- .withDeclaration("abstract class %s { %s }");
- }
-
- static Factory daggerModuleMethod() {
- return new Factory();
- }
-
- private Factory() {}
-
- @Override
- public DaggerModuleMethodSubject createSubject(FailureMetadata failureMetadata, String that) {
- return new DaggerModuleMethodSubject(failureMetadata, that);
- }
- }
-
- private final String actual;
- private final ImmutableList.Builder<String> imports =
- new ImmutableList.Builder<String>()
- .add(
- // explicitly import Module so it's not ambiguous with java.lang.Module
- "import dagger.Module;",
- "import dagger.*;",
- "import dagger.multibindings.*;",
- "import dagger.producers.*;",
- "import java.util.*;",
- "import javax.inject.*;");
- private String declaration;
- private ImmutableList<JavaFileObject> additionalSources = ImmutableList.of();
-
- private DaggerModuleMethodSubject(FailureMetadata failureMetadata, String subject) {
- super(failureMetadata, subject);
- this.actual = subject;
- }
-
- /**
- * Imports classes and interfaces. Note that all types in the following packages are already
- * imported:<ul>
- * <li>{@code dagger.*}
- * <li>{@code dagger.multibindings.*}
- * <li>(@code dagger.producers.*}
- * <li>{@code java.util.*}
- * <li>{@code javax.inject.*}
- * </ul>
- */
- DaggerModuleMethodSubject importing(Class<?>... imports) {
- return importing(Arrays.asList(imports));
- }
-
- /**
- * Imports classes and interfaces. Note that all types in the following packages are already
- * imported:<ul>
- * <li>{@code dagger.*}
- * <li>{@code dagger.multibindings.*}
- * <li>(@code dagger.producers.*}
- * <li>{@code java.util.*}
- * <li>{@code javax.inject.*}
- * </ul>
- */
- DaggerModuleMethodSubject importing(List<? extends Class<?>> imports) {
- imports.stream()
- .map(clazz -> String.format("import %s;", clazz.getCanonicalName()))
- .forEachOrdered(this.imports::add);
- return this;
- }
-
- /**
- * Sets the declaration of the module. Must be a string with two {@code %s} parameters. The first
- * will be replaced with the name of the type, and the second with the method declaration, which
- * must be within paired braces.
- */
- DaggerModuleMethodSubject withDeclaration(String declaration) {
- this.declaration = declaration;
- return this;
- }
-
- /** Additional source files that must be compiled with the module. */
- DaggerModuleMethodSubject withAdditionalSources(JavaFileObject... sources) {
- this.additionalSources = ImmutableList.copyOf(sources);
- return this;
- }
-
- /**
- * Fails if compiling the module with the method doesn't report an error at the method
- * declaration whose message contains {@code errorSubstring}.
- */
- void hasError(String errorSubstring) {
- String source = moduleSource();
- JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule", source);
- Compilation compilation =
- daggerCompiler().compile(FluentIterable.from(additionalSources).append(module));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(errorSubstring)
- .inFile(module)
- .onLine(methodLine(source));
- }
-
- private int methodLine(String source) {
- String beforeMethod = source.substring(0, source.indexOf(actual));
- int methodLine = 1;
- for (int nextNewlineIndex = beforeMethod.indexOf('\n');
- nextNewlineIndex >= 0;
- nextNewlineIndex = beforeMethod.indexOf('\n', nextNewlineIndex + 1)) {
- methodLine++;
- }
- return methodLine;
- }
-
- private String moduleSource() {
- StringWriter stringWriter = new StringWriter();
- PrintWriter writer = new PrintWriter(stringWriter);
- writer.println("package test;");
- writer.println();
- for (String importLine : imports.build()) {
- writer.println(importLine);
- }
- writer.println();
- writer.printf(declaration, "TestModule", "\n" + actual + "\n");
- writer.println();
- return stringWriter.toString();
- }
-
-}
diff --git a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java b/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
deleted file mode 100644
index 2f4aecf..0000000
--- a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
+++ /dev/null
@@ -1,992 +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;
-
-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.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.CompilationSubject;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 DelegateBindingExpressionTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public DelegateBindingExpressionTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- private static final JavaFileObject REGULAR_SCOPED =
- JavaFileObjects.forSourceLines(
- "test.RegularScoped",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "import javax.inject.Inject;",
- "",
- "@RegularScoped.CustomScope",
- "class RegularScoped {",
- " @Inject RegularScoped() {}",
- "",
- " @Scope @interface CustomScope {}",
- "}");
-
- private static final JavaFileObject REUSABLE_SCOPED =
- JavaFileObjects.forSourceLines(
- "test.ReusableScoped",
- "package test;",
- "",
- "import dagger.Reusable;",
- "import javax.inject.Inject;",
- "",
- "@Reusable",
- "class ReusableScoped {",
- " @Inject ReusableScoped() {}",
- "}");
-
- private static final JavaFileObject UNSCOPED =
- JavaFileObjects.forSourceLines(
- "test.Unscoped",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Unscoped {",
- " @Inject Unscoped() {}",
- "}");
-
- private static final JavaFileObject COMPONENT =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "@RegularScoped.CustomScope",
- "interface TestComponent {",
- " @Qualifier(RegularScoped.class)",
- " Object regular();",
- "",
- " @Qualifier(ReusableScoped.class)",
- " Object reusable();",
- "",
- " @Qualifier(Unscoped.class)",
- " Object unscoped();",
- "}");
-
- private static final JavaFileObject QUALIFIER =
- JavaFileObjects.forSourceLines(
- "test.Qualifier",
- "package test;",
- "",
- "@javax.inject.Qualifier",
- "@interface Qualifier {",
- " Class<?> value();",
- "}");
-
- @Test
- public void toDoubleCheck() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface TestModule {",
- " @Binds @RegularScoped.CustomScope @Qualifier(RegularScoped.class)",
- " Object regular(RegularScoped delegate);",
- "",
- " @Binds @RegularScoped.CustomScope @Qualifier(ReusableScoped.class)",
- " Object reusable(ReusableScoped delegate);",
- "",
- " @Binds @RegularScoped.CustomScope @Qualifier(Unscoped.class)",
- " Object unscoped(Unscoped delegate);",
- "}");
-
- assertThatCompilationWithModule(module)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped getRegularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped getReusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.regularScopedProvider = ",
- " DoubleCheck.provider(RegularScoped_Factory.create());",
- " this.reusableScopedProvider = ",
- " SingleCheck.provider(ReusableScoped_Factory.create());",
- " this.reusableProvider = DoubleCheck.provider(",
- " (Provider) reusableScopedProvider);",
- " this.unscopedProvider = DoubleCheck.provider(",
- " (Provider) Unscoped_Factory.create());",
- " }")
- .addLines( //
- "}")
- .build());
- }
-
- @Test
- public void toSingleCheck() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Reusable;",
- "",
- "@Module",
- "interface TestModule {",
- " @Binds @Reusable @Qualifier(RegularScoped.class)",
- " Object regular(RegularScoped delegate);",
- "",
- " @Binds @Reusable @Qualifier(ReusableScoped.class)",
- " Object reusable(ReusableScoped delegate);",
- "",
- " @Binds @Reusable @Qualifier(Unscoped.class)",
- " Object unscoped(Unscoped delegate);",
- "}");
-
- assertThatCompilationWithModule(module)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped getRegularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped getReusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.regularScopedProvider = ",
- " DoubleCheck.provider(RegularScoped_Factory.create());",
- " this.reusableScopedProvider = ",
- " SingleCheck.provider(ReusableScoped_Factory.create());",
- " this.unscopedProvider = SingleCheck.provider(",
- " (Provider) Unscoped_Factory.create());",
- " }")
- .addLines( //
- "}")
- .build());
- }
-
- @Test
- public void toUnscoped() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface TestModule {",
- " @Binds @Qualifier(RegularScoped.class)",
- " Object regular(RegularScoped delegate);",
- "",
- " @Binds @Qualifier(ReusableScoped.class)",
- " Object reusable(ReusableScoped delegate);",
- "",
- " @Binds @Qualifier(Unscoped.class)",
- " Object unscoped(Unscoped delegate);",
- "}");
-
- assertThatCompilationWithModule(module)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object regularScoped = new MemoizedSentinel();",
- " private volatile ReusableScoped reusableScoped;",
- "",
- " private RegularScoped getRegularScoped() {",
- " Object local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = regularScoped;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new RegularScoped();",
- " regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
- " }",
- " }",
- " }",
- " return (RegularScoped) local;",
- " }",
- "",
- " private ReusableScoped getReusableScoped() {",
- " Object local = reusableScoped;",
- " if (local == null) {",
- " local = new ReusableScoped();",
- " reusableScoped = (ReusableScoped) local;",
- " }",
- " return (ReusableScoped) local;",
- " }",
- "")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.regularScopedProvider = ",
- " DoubleCheck.provider(RegularScoped_Factory.create());",
- " this.reusableScopedProvider = ",
- " SingleCheck.provider(ReusableScoped_Factory.create());",
- " }")
- .addLines( //
- "}")
- .build());
- }
-
- @Test
- public void castNeeded_rawTypes_Provider_get() {
- JavaFileObject accessibleSupertype =
- JavaFileObjects.forSourceLines(
- "other.Supertype",
- "package other;",
- "",
- // accessible from the component, but the subtype is not
- "public interface Supertype {}");
- JavaFileObject inaccessibleSubtype =
- JavaFileObjects.forSourceLines(
- "other.Subtype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "class Subtype implements Supertype {",
- " @Inject Subtype() {}",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.SupertypeModule",
- "package other;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "public interface SupertypeModule {",
- " @Binds Supertype to(Subtype subtype);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = other.SupertypeModule.class)",
- "interface TestComponent {",
- " other.Supertype supertype();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(accessibleSupertype, inaccessibleSubtype, module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider subtypeProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.subtypeProvider = DoubleCheck.provider(Subtype_Factory.create());",
- " }",
- "",
- " @Override",
- " public Supertype supertype() {",
- " return (Supertype) subtypeProvider.get();",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object subtype = new MemoizedSentinel();",
- "",
- " private Object getSubtype() {",
- " Object local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " local = Subtype_Factory.newInstance();",
- " subtype = DoubleCheck.reentrantCheck(subtype, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
- " @Override",
- " public Supertype supertype() {",
- " return (Supertype) getSubtype();",
- " }")
- .build());
- }
-
- @Test
- public void noCast_rawTypes_Provider_get_toInaccessibleType() {
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "other.Supertype",
- "package other;",
- "",
- "interface Supertype {}");
- JavaFileObject subtype =
- JavaFileObjects.forSourceLines(
- "other.Subtype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "class Subtype implements Supertype {",
- " @Inject Subtype() {}",
- "}");
- JavaFileObject usesSupertype =
- JavaFileObjects.forSourceLines(
- "other.UsesSupertype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class UsesSupertype {",
- " @Inject UsesSupertype(Supertype supertype) {}",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.SupertypeModule",
- "package other;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "public interface SupertypeModule {",
- " @Binds Supertype to(Subtype subtype);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = other.SupertypeModule.class)",
- "interface TestComponent {",
- " other.UsesSupertype usesSupertype();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(supertype, subtype, usesSupertype, module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider subtypeProvider;",
- "",
- " @Override",
- " public UsesSupertype usesSupertype() {",
- // can't cast the provider.get() to a type that's not accessible
- " return UsesSupertype_Factory.newInstance(subtypeProvider.get());",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object subtype = new MemoizedSentinel();",
- "",
- " private Object getSubtype() {",
- " Object local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = subtype;",
- " if (local instanceof MemoizedSentinel) {",
- " local = Subtype_Factory.newInstance();",
- " subtype = DoubleCheck.reentrantCheck(subtype, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
- " @Override",
- " public UsesSupertype usesSupertype() {",
- " return UsesSupertype_Factory.newInstance(getSubtype());",
- " }")
- .build());
- }
-
- @Test
- public void castedToRawType() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Named;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String provideString() { return new String(); }",
- "",
- " @Binds",
- " CharSequence charSequence(String string);",
- "",
- " @Binds",
- " @Named(\"named\")",
- " String namedString(String string);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Named;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<CharSequence> charSequence();",
- "",
- " @Named(\"named\") Provider<String> namedString();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " @Override",
- " public Provider<CharSequence> charSequence() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
- " }",
- "",
- " @Override",
- " public Provider<String> namedString() {",
- " return TestModule_ProvideStringFactory.create();",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<String> provideStringProvider;",
- "",
- " private Provider<String> getStringProvider() {",
- " Object local = provideStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideStringProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
- " }",
- "",
- " @Override",
- " public Provider<CharSequence> charSequence() {",
- " return (Provider) getStringProvider();",
- " }",
- "",
- " @Override",
- " public Provider<String> namedString() {",
- " return getStringProvider();",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) TestModule_ProvideStringFactory.provideString();",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build());
- }
-
- @Test
- public void doubleBinds() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String provideString() { return new String(); }",
- "",
- " @Binds",
- " CharSequence charSequence(String string);",
- "",
- " @Binds",
- " Object object(CharSequence charSequence);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Named;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<CharSequence> charSequence();",
- " Provider<Object> object();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " @Override",
- " public Provider<CharSequence> charSequence() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
- " }",
- " @Override",
- " public Provider<Object> object() {",
- " return (Provider) TestModule_ProvideStringFactory.create();",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<String> provideStringProvider;",
- "",
- " private Provider<String> getStringProvider() {",
- " Object local = provideStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideStringProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
- " }",
- "",
- " @Override",
- " public Provider<CharSequence> charSequence() {",
- " return (Provider) getStringProvider();",
- " }",
- "",
- " @Override",
- " public Provider<Object> object() {",
- " return (Provider) getStringProvider();",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) TestModule_ProvideStringFactory.provideString();",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build());
- }
-
- @Test
- public void inlineFactoryOfInacessibleType() {
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "other.Supertype", "package other;", "", "public interface Supertype {}");
- JavaFileObject injectableSubtype =
- JavaFileObjects.forSourceLines(
- "other.Subtype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class Subtype implements Supertype {",
- // important: this doesn't have any dependencies and therefore the factory will be able
- // to be referenced with an inline Subtype_Factory.create()
- " @Inject Subtype() {}",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "public interface TestModule {",
- " @Binds Supertype to(Subtype subtype);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.RequestsSubtypeAsProvider",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = other.TestModule.class)",
- "interface RequestsSubtypeAsProvider {",
- " Provider<other.Supertype> supertypeProvider();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(supertype, injectableSubtype, module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerRequestsSubtypeAsProvider")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerRequestsSubtypeAsProvider")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerRequestsSubtypeAsProvider",
- " implements RequestsSubtypeAsProvider {")
- .addLinesIn(
- DEFAULT_MODE,
- " @Override",
- " public Provider<Supertype> supertypeProvider() {",
- " return (Provider) Subtype_Factory.create();",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider subtypeProvider;",
- "",
- " private Provider getSubtypeProvider() {",
- " Object local = subtypeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " subtypeProvider = (Provider) local;",
- " }",
- " return (Provider) local;",
- " }",
- "",
- " @Override",
- " public Provider<Supertype> supertypeProvider() {",
- " return getSubtypeProvider();",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) Subtype_Factory.newInstance();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build());
- }
-
- @Test
- public void providerWhenBindsScopeGreaterThanDependencyScope() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Reusable;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Reusable",
- " @Provides",
- " static String provideString() {",
- " return \"\";",
- " }",
- "",
- " @Binds",
- " @Singleton",
- " abstract Object bindString(String str);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "import javax.inject.Provider;",
- "",
- "@Singleton",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<Object> getObject();",
- "}");
-
- Compilation compilation = daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " private Provider<String> provideStringProvider;",
- " private Provider<Object> bindStringProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.provideStringProvider =",
- " SingleCheck.provider(TestModule_ProvideStringFactory.create());",
- " this.bindStringProvider =",
- " DoubleCheck.provider((Provider) provideStringProvider);",
- " }",
- "",
- " @Override",
- " public Provider<Object> getObject() {",
- " return bindStringProvider;",
- " }",
- "}")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile String string;",
- " private volatile Object object = new MemoizedSentinel();",
- " private volatile Provider<Object> bindStringProvider;",
- "",
- " private String getString() {",
- " Object local = string;",
- " if (local == null) {",
- " local = TestModule_ProvideStringFactory.provideString();",
- " string = (String) local;",
- " }",
- " return (String) local;",
- " }",
- "",
- " private Object getObject2() {",
- " Object local = object;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = object;",
- " if (local instanceof MemoizedSentinel) {",
- " local = getString();",
- " object = DoubleCheck.reentrantCheck(object, local);",
- " }",
- " }",
- " }",
- " return (Object) local;",
- " }",
- "",
- " @Override",
- " public Provider<Object> getObject() {",
- " Object local = bindStringProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " bindStringProvider = (Provider<Object>) local;",
- " }",
- " return (Provider<Object>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.getObject2();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }")
- .build());
- }
-
- private CompilationSubject assertThatCompilationWithModule(JavaFileObject module) {
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- module,
- COMPONENT,
- QUALIFIER,
- REGULAR_SCOPED,
- REUSABLE_SCOPED,
- UNSCOPED);
- assertThat(compilation).succeeded();
- return assertThat(compilation);
- }
-}
diff --git a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
deleted file mode 100644
index 4a4e0a5..0000000
--- a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
+++ /dev/null
@@ -1,699 +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 dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.endsWithMessage;
-import static dagger.internal.codegen.TestUtils.message;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.regex.Pattern;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DependencyCycleValidationTest {
- private static final JavaFileObject SIMPLE_CYCLIC_DEPENDENCY =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " static class A {",
- " @Inject A(C cParam) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(A aParam) {}",
- " }",
- "",
- " static class C {",
- " @Inject C(B bParam) {}",
- " }",
- "",
- " @Module",
- " interface MModule {",
- " @Binds Object object(C c);",
- " }",
- "",
- " @Component",
- " interface CComponent {",
- " C getC();",
- " }",
- "}");
-
- @Test
- public void cyclicDependency() {
- Compilation compilation = daggerCompiler().compile(SIMPLE_CYCLIC_DEPENDENCY);
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @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 provided at
- // test.Outer.CComponent.getC()", as the previous test's message does.
- Pattern moduleBindingValidationError =
- endsWithMessage(
- "Found a dependency cycle:",
- " 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 =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(SIMPLE_CYCLIC_DEPENDENCY);
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(moduleBindingValidationError)
- .inFile(SIMPLE_CYCLIC_DEPENDENCY)
- .onLineContaining("interface MModule");
-
- assertThat(compilation)
- .hadErrorContainingMatch(moduleBindingValidationError)
- .inFile(SIMPLE_CYCLIC_DEPENDENCY)
- .onLineContaining("interface CComponent");
-
- assertThat(compilation).hadErrorCount(2);
- }
-
- @Test public void cyclicDependencyNotIncludingEntryPoint() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " static class A {",
- " @Inject A(C cParam) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(A aParam) {}",
- " }",
- "",
- " static class C {",
- " @Inject C(B bParam) {}",
- " }",
- "",
- " static class D {",
- " @Inject D(C cParam) {}",
- " }",
- "",
- " @Component",
- " interface DComponent {",
- " D getD();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void cyclicDependencyNotBrokenByMapBinding() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.Map;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " static class A {",
- " @Inject A(Map<String, C> cMap) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(A aParam) {}",
- " }",
- "",
- " static class C {",
- " @Inject C(B bParam) {}",
- " }",
- "",
- " @Component(modules = CModule.class)",
- " interface CComponent {",
- " C getC();",
- " }",
- "",
- " @Module",
- " static class CModule {",
- " @Provides @IntoMap",
- " @StringKey(\"C\")",
- " static C c(C c) {",
- " return c;",
- " }",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void cyclicDependencyWithSetBinding() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " static class A {",
- " @Inject A(Set<C> cSet) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(A aParam) {}",
- " }",
- "",
- " static class C {",
- " @Inject C(B bParam) {}",
- " }",
- "",
- " @Component(modules = CModule.class)",
- " interface CComponent {",
- " C getC();",
- " }",
- "",
- " @Module",
- " static class CModule {",
- " @Provides @IntoSet",
- " static C c(C c) {",
- " return c;",
- " }",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void falsePositiveCyclicDependencyIndirectionDetected() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class Outer {",
- " static class A {",
- " @Inject A(C cParam) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(A aParam) {}",
- " }",
- "",
- " static class C {",
- " @Inject C(B bParam) {}",
- " }",
- "",
- " static class D {",
- " @Inject D(Provider<C> cParam) {}",
- " }",
- "",
- " @Component",
- " interface DComponent {",
- " D getD();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void cyclicDependencyInSubcomponents() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Child.Builder child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = CycleModule.class)",
- "interface Child {",
- " Grandchild.Builder grandchild();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "}");
- JavaFileObject grandchild =
- JavaFileObjects.forSourceLines(
- "test.Grandchild",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Grandchild {",
- " String entry();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Grandchild build();",
- " }",
- "}");
- JavaFileObject cycleModule =
- JavaFileObjects.forSourceLines(
- "test.CycleModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class CycleModule {",
- " @Provides static Object object(String string) {",
- " return string;",
- " }",
- "",
- " @Provides static String string(Object object) {",
- " return object.toString();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, child, grandchild, cycleModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void cyclicDependencyInSubcomponentsWithChildren() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Child.Builder child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = CycleModule.class)",
- "interface Child {",
- " String entry();",
- "",
- " Grandchild.Builder grandchild();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "}");
- // Grandchild has no entry point that depends on the cycle. http://b/111317986
- JavaFileObject grandchild =
- JavaFileObjects.forSourceLines(
- "test.Grandchild",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Grandchild {",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Grandchild build();",
- " }",
- "}");
- JavaFileObject cycleModule =
- JavaFileObjects.forSourceLines(
- "test.CycleModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class CycleModule {",
- " @Provides static Object object(String string) {",
- " return string;",
- " }",
- "",
- " @Provides static String string(Object object) {",
- " return object.toString();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, child, grandchild, cycleModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void circularBindsMethods() {
- JavaFileObject qualifier =
- JavaFileObjects.forSourceLines(
- "test.SomeQualifier",
- "package test;",
- "",
- "import javax.inject.Qualifier;",
- "",
- "@Qualifier @interface SomeQualifier {}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Binds abstract Object bindUnqualified(@SomeQualifier Object qualified);",
- " @Binds @SomeQualifier abstract Object bindQualified(Object unqualified);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Object unqualified();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(qualifier, module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " 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");
- }
-
- @Test
- public void selfReferentialBinds() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Binds abstract Object bindToSelf(Object sameKey);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Object selfReferential();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " java.lang.Object is injected at",
- " test.TestModule.bindToSelf(sameKey)",
- " java.lang.Object is provided at",
- " test.TestComponent.selfReferential()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void cycleFromMembersInjectionMethod_WithSameKeyAsMembersInjectionMethod() {
- JavaFileObject a =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class A {",
- " @Inject A() {}",
- " @Inject B b;",
- "}");
- JavaFileObject b =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class B {",
- " @Inject B() {}",
- " @Inject A a;",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.CycleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface CycleComponent {",
- " void inject(A a);",
- "}");
-
- Compilation compilation = daggerCompiler().compile(a, b, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "Found a dependency cycle:",
- " test.B is injected at",
- " test.A.b",
- " test.A is injected at",
- " test.B.a",
- " test.B is injected at",
- " test.A.b",
- " test.A is injected at",
- " test.CycleComponent.inject(test.A)"))
- .inFile(component)
- .onLineContaining("interface CycleComponent");
- }
-
- @Test
- public void longCycleMaskedByShortBrokenCycles() {
- JavaFileObject cycles =
- JavaFileObjects.forSourceLines(
- "test.Cycles",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "import dagger.Component;",
- "",
- "final class Cycles {",
- " static class A {",
- " @Inject A(Provider<A> aProvider, B b) {}",
- " }",
- "",
- " static class B {",
- " @Inject B(Provider<B> bProvider, A a) {}",
- " }",
- "",
- " @Component",
- " interface C {",
- " A a();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(cycles);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Found a dependency cycle:")
- .inFile(cycles)
- .onLineContaining("interface C");
- }
-}
diff --git a/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java b/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java
deleted file mode 100644
index a2da92f..0000000
--- a/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java
+++ /dev/null
@@ -1,32 +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;
-
-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 DiagnosticFormattingTest {
- @Test public void stripCommonTypePrefixes() {
- String typeName = "com.google.common.collect.ImmutableList<java.lang.Boolean>";
- assertThat(DiagnosticFormatting.stripCommonTypePrefixes(typeName))
- .isEqualTo("ImmutableList<Boolean>");
- }
-}
diff --git a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
deleted file mode 100644
index 14a6fb9..0000000
--- a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
+++ /dev/null
@@ -1,1083 +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 dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.message;
-import static org.junit.Assume.assumeFalse;
-
-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.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class DuplicateBindingsValidationTest {
-
- @Parameters(name = "fullBindingGraphValidation={0}")
- public static ImmutableList<Object[]> parameters() {
- return ImmutableList.copyOf(new Object[][] {{false}, {true}});
- }
-
- private final boolean fullBindingGraphValidation;
-
- public DuplicateBindingsValidationTest(boolean fullBindingGraphValidation) {
- this.fullBindingGraphValidation = fullBindingGraphValidation;
- }
-
- @Test public void duplicateExplicitBindings_ProvidesAndComponentProvision() {
- assumeFalse(fullBindingGraphValidation);
-
- JavaFileObject component = JavaFileObjects.forSourceLines("test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "final class Outer {",
- " interface A {}",
- "",
- " interface B {}",
- "",
- " @Module",
- " static class AModule {",
- " @Provides String provideString() { return \"\"; }",
- " @Provides A provideA(String s) { return new A() {}; }",
- " }",
- "",
- " @Component(modules = AModule.class)",
- " interface Parent {",
- " A getA();",
- " }",
- "",
- " @Module",
- " static class BModule {",
- " @Provides B provideB(A a) { return new B() {}; }",
- " }",
- "",
- " @Component(dependencies = Parent.class, modules = { BModule.class, AModule.class})",
- " interface Child {",
- " B getB();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
- }
-
- @Test public void duplicateExplicitBindings_TwoProvidesMethods() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " interface A {}",
- "",
- " static class B {",
- " @Inject B(A a) {}",
- " }",
- "",
- " @Module",
- " static class Module1 {",
- " @Provides A provideA1() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module2 {",
- " @Provides String provideString() { return \"\"; }",
- " @Provides A provideA2(String s) { return new A() {}; }",
- " }",
- "",
- " @Module(includes = { Module1.class, Module2.class})",
- " abstract static class Module3 {}",
- "",
- " @Component(modules = { Module1.class, Module2.class})",
- " interface TestComponent {",
- " A getA();",
- " B getB();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
-
- if (fullBindingGraphValidation) {
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
- }
-
- // The duplicate bindngs are also requested from B, but we don't want to report them again.
- assertThat(compilation).hadErrorCount(fullBindingGraphValidation ? 2 : 1);
- }
-
- @Test
- public void duplicateExplicitBindings_ProvidesVsBinds() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " interface A {}",
- "",
- " static final class B implements A {",
- " @Inject B() {}",
- " }",
- "",
- " @Module",
- " static class Module1 {",
- " @Provides A provideA1() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static abstract class Module2 {",
- " @Binds abstract A bindA2(B b);",
- " }",
- "",
- " @Module(includes = { Module1.class, Module2.class})",
- " abstract static class Module3 {}",
- "",
- " @Component(modules = { Module1.class, Module2.class})",
- " interface TestComponent {",
- " A getA();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
-
- if (fullBindingGraphValidation) {
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
- }
- }
-
- @Test
- public void duplicateExplicitBindings_multibindingsAndExplicitSets() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.HashSet;",
- "import java.util.Set;",
- "import javax.inject.Qualifier;",
- "",
- "final class Outer {",
- " @Qualifier @interface SomeQualifier {}",
- "",
- " @Module",
- " abstract static class TestModule1 {",
- " @Provides @IntoSet static String stringSetElement() { return \"\"; }",
- "",
- " @Binds",
- " @IntoSet abstract String bindStringSetElement(@SomeQualifier String value);",
- "",
- " @Provides @SomeQualifier",
- " static String provideSomeQualifiedString() { return \"\"; }",
- " }",
- "",
- " @Module",
- " static class TestModule2 {",
- " @Provides Set<String> stringSet() { return new HashSet<String>(); }",
- " }",
- "",
- " @Module(includes = { TestModule1.class, TestModule2.class})",
- " abstract static class TestModule3 {}",
- "",
- " @Component(modules = { TestModule1.class, TestModule2.class })",
- " interface TestComponent {",
- " Set<String> getStringSet();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.util.Set<java.lang.String> has incompatible bindings or declarations:",
- " Set bindings and declarations:",
- " @Binds @dagger.multibindings.IntoSet String "
- + "test.Outer.TestModule1.bindStringSetElement(@test.Outer.SomeQualifier "
- + "String)",
- " @Provides @dagger.multibindings.IntoSet String "
- + "test.Outer.TestModule1.stringSetElement()",
- " Unique bindings and declarations:",
- " @Provides Set<String> test.Outer.TestModule2.stringSet()"))
- .inFile(component)
- .onLineContaining(
- fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
- }
-
- @Test
- public void duplicateExplicitBindings_multibindingsAndExplicitMaps() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.HashMap;",
- "import java.util.Map;",
- "import javax.inject.Qualifier;",
- "",
- "final class Outer {",
- " @Qualifier @interface SomeQualifier {}",
- "",
- " @Module",
- " abstract static class TestModule1 {",
- " @Provides @IntoMap",
- " @StringKey(\"foo\")",
- " static String stringMapEntry() { return \"\"; }",
- "",
- " @Binds @IntoMap @StringKey(\"bar\")",
- " abstract String bindStringMapEntry(@SomeQualifier String value);",
- "",
- " @Provides @SomeQualifier",
- " static String provideSomeQualifiedString() { return \"\"; }",
- " }",
- "",
- " @Module",
- " static class TestModule2 {",
- " @Provides Map<String, String> stringMap() {",
- " return new HashMap<String, String>();",
- " }",
- " }",
- "",
- " @Module(includes = { TestModule1.class, TestModule2.class})",
- " abstract static class TestModule3 {}",
- "",
- " @Component(modules = { TestModule1.class, TestModule2.class })",
- " interface TestComponent {",
- " Map<String, String> getStringMap();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings "
- + "or declarations:",
- " Map bindings and declarations:",
- " @Binds @dagger.multibindings.IntoMap "
- + "@dagger.multibindings.StringKey(\"bar\") String"
- + " test.Outer.TestModule1.bindStringMapEntry(@test.Outer.SomeQualifier "
- + "String)",
- " @Provides @dagger.multibindings.IntoMap "
- + "@dagger.multibindings.StringKey(\"foo\") String"
- + " test.Outer.TestModule1.stringMapEntry()",
- " Unique bindings and declarations:",
- " @Provides Map<String,String> test.Outer.TestModule2.stringMap()"))
- .inFile(component)
- .onLineContaining(
- fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
- }
-
- @Test
- public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Set() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.HashSet;",
- "import java.util.Set;",
- "",
- "final class Outer {",
- " @Module",
- " abstract static class TestModule1 {",
- " @Multibinds abstract Set<String> stringSet();",
- " }",
- "",
- " @Module",
- " static class TestModule2 {",
- " @Provides Set<String> stringSet() { return new HashSet<String>(); }",
- " }",
- "",
- " @Module(includes = { TestModule1.class, TestModule2.class})",
- " abstract static class TestModule3 {}",
- "",
- " @Component(modules = { TestModule1.class, TestModule2.class })",
- " interface TestComponent {",
- " Set<String> getStringSet();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.util.Set<java.lang.String> has incompatible bindings or declarations:",
- " Set bindings and declarations:",
- " @dagger.multibindings.Multibinds Set<String> "
- + "test.Outer.TestModule1.stringSet()",
- " Unique bindings and declarations:",
- " @Provides Set<String> test.Outer.TestModule2.stringSet()"))
- .inFile(component)
- .onLineContaining(
- fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
- }
-
- @Test
- public void duplicateExplicitBindings_UniqueBindingAndMultibindingDeclaration_Map() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.HashMap;",
- "import java.util.Map;",
- "",
- "final class Outer {",
- " @Module",
- " abstract static class TestModule1 {",
- " @Multibinds abstract Map<String, String> stringMap();",
- " }",
- "",
- " @Module",
- " static class TestModule2 {",
- " @Provides Map<String, String> stringMap() {",
- " return new HashMap<String, String>();",
- " }",
- " }",
- "",
- " @Module(includes = { TestModule1.class, TestModule2.class})",
- " abstract static class TestModule3 {}",
- "",
- " @Component(modules = { TestModule1.class, TestModule2.class })",
- " interface TestComponent {",
- " Map<String, String> getStringMap();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings "
- + "or declarations:",
- " Map bindings and declarations:",
- " @dagger.multibindings.Multibinds Map<String,String> "
- + "test.Outer.TestModule1.stringMap()",
- " Unique bindings and declarations:",
- " @Provides Map<String,String> test.Outer.TestModule2.stringMap()"))
- .inFile(component)
- .onLineContaining(
- fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
- }
-
- @Test public void duplicateBindings_TruncateAfterLimit() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Outer",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class Outer {",
- " interface A {}",
- "",
- " @Module",
- " static class Module01 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module02 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module03 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module04 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module05 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module06 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module07 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module08 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module09 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module10 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module11 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module",
- " static class Module12 {",
- " @Provides A provideA() { return new A() {}; }",
- " }",
- "",
- " @Module(includes = {",
- " Module01.class,",
- " Module02.class,",
- " Module03.class,",
- " Module04.class,",
- " Module05.class,",
- " Module06.class,",
- " Module07.class,",
- " Module08.class,",
- " Module09.class,",
- " Module10.class,",
- " Module11.class,",
- " Module12.class",
- " })",
- " abstract static class Modules {}",
- "",
- " @Component(modules = {",
- " Module01.class,",
- " Module02.class,",
- " Module03.class,",
- " Module04.class,",
- " Module05.class,",
- " Module06.class,",
- " Module07.class,",
- " Module08.class,",
- " Module09.class,",
- " Module10.class,",
- " Module11.class,",
- " Module12.class",
- " })",
- " interface TestComponent {",
- " A getA();",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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");
- }
-
- @Test
- public void childBindingConflictsWithParent() {
- JavaFileObject aComponent =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Component(modules = A.AModule.class)",
- "interface A {",
- " Object conflict();",
- "",
- " B.Builder b();",
- "",
- " @Module(subcomponents = B.class)",
- " static class AModule {",
- " @Provides static Object abConflict() {",
- " return \"a\";",
- " }",
- " }",
- "}");
- JavaFileObject bComponent =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = B.BModule.class)",
- "interface B {",
- " Object conflict();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " B build();",
- " }",
- "",
- " @Module",
- " static class BModule {",
- " @Provides static Object abConflict() {",
- " return \"b\";",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(fullBindingGraphValidationOption())
- .compile(aComponent, bComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.lang.Object is bound multiple times:",
- " @Provides Object test.A.AModule.abConflict()",
- " @Provides Object test.B.BModule.abConflict()"))
- .inFile(aComponent)
- .onLineContaining(fullBindingGraphValidation ? "class AModule" : "interface A {");
- }
-
- @Test
- public void grandchildBindingConflictsWithGrandparent() {
- JavaFileObject aComponent =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Component(modules = A.AModule.class)",
- "interface A {",
- " Object conflict();",
- "",
- " B.Builder b();",
- "",
- " @Module(subcomponents = B.class)",
- " static class AModule {",
- " @Provides static Object acConflict() {",
- " return \"a\";",
- " }",
- " }",
- "}");
- JavaFileObject bComponent =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface B {",
- " C.Builder c();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " B build();",
- " }",
- "}");
- JavaFileObject cComponent =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = C.CModule.class)",
- "interface C {",
- " Object conflict();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " C build();",
- " }",
- "",
- " @Module",
- " static class CModule {",
- " @Provides static Object acConflict() {",
- " return \"c\";",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(fullBindingGraphValidationOption())
- .compile(aComponent, bComponent, cComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.lang.Object is bound multiple times:",
- " @Provides Object test.A.AModule.acConflict()",
- " @Provides Object test.C.CModule.acConflict()"))
- .inFile(aComponent)
- .onLineContaining(fullBindingGraphValidation ? "class AModule" : "interface A {");
- }
-
- @Test
- public void grandchildBindingConflictsWithChild() {
- JavaFileObject aComponent =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface A {",
- " B b();",
- "}");
- JavaFileObject bComponent =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = B.BModule.class)",
- "interface B {",
- " Object conflict();",
- "",
- " C.Builder c();",
- "",
- " @Module(subcomponents = C.class)",
- " static class BModule {",
- " @Provides static Object bcConflict() {",
- " return \"b\";",
- " }",
- " }",
- "}");
- JavaFileObject cComponent =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = C.CModule.class)",
- "interface C {",
- " Object conflict();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " C build();",
- " }",
- "",
- " @Module",
- " static class CModule {",
- " @Provides static Object bcConflict() {",
- " return \"c\";",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(fullBindingGraphValidationOption())
- .compile(aComponent, bComponent, cComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.lang.Object is bound multiple times:",
- " @Provides Object test.B.BModule.bcConflict()",
- " @Provides Object test.C.CModule.bcConflict()"))
- .inFile(fullBindingGraphValidation ? bComponent : aComponent)
- .onLineContaining(fullBindingGraphValidation ? "class BModule" : "interface A {");
- }
-
- @Test
- public void childProvidesConflictsWithParentInjects() {
- assumeFalse(fullBindingGraphValidation);
-
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import java.util.Set;",
- "import javax.inject.Inject;",
- "",
- "final class Foo {",
- " @Inject Foo(Set<String> strings) {}",
- "}");
- JavaFileObject injected1 =
- JavaFileObjects.forSourceLines(
- "test.Injected1",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "",
- "@Component(modules = Injected1.Injected1Module.class)",
- "interface Injected1 {",
- " Foo foo();",
- " Injected2 injected2();",
- "",
- " @Module",
- " interface Injected1Module {",
- " @Provides @IntoSet static String string() {",
- " return \"injected1\";",
- " }",
- " }",
- "}");
- JavaFileObject injected2 =
- JavaFileObjects.forSourceLines(
- "test.Injected2",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "",
- "@Subcomponent(modules = Injected2.Injected2Module.class)",
- "interface Injected2 {",
- " Foo foo();",
- " Provided1 provided1();",
- "",
- " @Module",
- " interface Injected2Module {",
- " @Provides @IntoSet static String string() {",
- " return \"injected2\";",
- " }",
- " }",
- "}");
- JavaFileObject provided1 =
- JavaFileObjects.forSourceLines(
- "test.Provided1",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "",
- "@Subcomponent(modules = Provided1.Provided1Module.class)",
- "interface Provided1 {",
- " Foo foo();",
- " Provided2 provided2();",
- "",
- " @Module",
- " static class Provided1Module {",
- " @Provides static Foo provideFoo(Set<String> strings) {",
- " return new Foo(strings);",
- " }",
- "",
- " @Provides @IntoSet static String string() {",
- " return \"provided1\";",
- " }",
- " }",
- "}");
- JavaFileObject provided2 =
- JavaFileObjects.forSourceLines(
- "test.Provided2",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Subcomponent(modules = Provided2.Provided2Module.class)",
- "interface Provided2 {",
- " Foo foo();",
- "",
- " @Module",
- " static class Provided2Module {",
- " @Provides @IntoSet static String string() {",
- " return \"provided2\";",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(foo, injected1, injected2, provided1, provided2);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining(
- message(
- "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 {");
- }
-
- @Test
- public void grandchildBindingConflictsWithParentWithNullableViolationAsWarning() {
- JavaFileObject parentConflictsWithChild =
- JavaFileObjects.forSourceLines(
- "test.ParentConflictsWithChild",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.annotation.Nullable;",
- "",
- "@Component(modules = ParentConflictsWithChild.ParentModule.class)",
- "interface ParentConflictsWithChild {",
- " Child.Builder child();",
- "",
- " @Module(subcomponents = Child.class)",
- " static class ParentModule {",
- " @Provides @Nullable static Object nullableParentChildConflict() {",
- " return \"parent\";",
- " }",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = Child.ChildModule.class)",
- "interface Child {",
- " Object parentChildConflictThatViolatesNullability();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "",
- " @Module",
- " static class ChildModule {",
- " @Provides static Object nonNullableParentChildConflict() {",
- " return \"child\";",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.nullableValidation=WARNING", fullBindingGraphValidationOption())
- .compile(parentConflictsWithChild, child);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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
- ? "class ParentModule"
- : "interface ParentConflictsWithChild");
- }
-
- private String fullBindingGraphValidationOption() {
- return "-Adagger.fullBindingGraphValidation=" + (fullBindingGraphValidation ? "ERROR" : "NONE");
- }
-
- @Test
- public void reportedInParentAndChild() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child.Builder childBuilder();",
- " String duplicated();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.BindsOptionalOf;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.Optional;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Provides static String one(Optional<Object> optional) { return \"one\"; }",
- " @Provides static String two() { return \"two\"; }",
- " @BindsOptionalOf Object optional();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface Child {",
- " String duplicated();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.Optional;",
- "",
- "@Module",
- "interface ChildModule {",
- " @Provides static Object object() { return \"object\"; }",
- "}");
- Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("java.lang.String is bound multiple times")
- .inFile(parent)
- .onLineContaining("interface Parent");
- assertThat(compilation).hadErrorCount(1);
- }
-}
diff --git a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java b/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
deleted file mode 100644
index 58ddb82..0000000
--- a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
+++ /dev/null
@@ -1,497 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 ElidedFactoriesTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ElidedFactoriesTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void simpleComponent() {
- JavaFileObject injectedType =
- JavaFileObjects.forSourceLines(
- "test.InjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class InjectedType {",
- " @Inject InjectedType() {}",
- "}");
-
- JavaFileObject dependsOnInjected =
- JavaFileObjects.forSourceLines(
- "test.InjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class DependsOnInjected {",
- " @Inject DependsOnInjected(InjectedType injected) {}",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " DependsOnInjected dependsOnInjected();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public DependsOnInjected dependsOnInjected() {",
- " return new DependsOnInjected(new InjectedType());",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {",
- " }",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(injectedType, dependsOnInjected, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void simpleComponent_injectsProviderOf_dependsOnScoped() {
- JavaFileObject scopedType =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class ScopedType {",
- " @Inject ScopedType() {}",
- "}");
-
- JavaFileObject dependsOnScoped =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class DependsOnScoped {",
- " @Inject DependsOnScoped(ScopedType scoped) {}",
- "}");
-
- JavaFileObject needsProvider =
- JavaFileObjects.forSourceLines(
- "test.NeedsProvider",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class NeedsProvider {",
- " @Inject NeedsProvider(Provider<DependsOnScoped> provider) {}",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface SimpleComponent {",
- " NeedsProvider needsProvider();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.MemoizedSentinel;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private volatile Object scopedType = new MemoizedSentinel();",
- " private volatile Provider<DependsOnScoped> dependsOnScopedProvider;",
- "",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private ScopedType getScopedType() {",
- " Object local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new ScopedType();",
- " scopedType = DoubleCheck.reentrantCheck(scopedType, local);",
- " }",
- " }",
- " }",
- " return (ScopedType) local;",
- " }",
- "",
- " private DependsOnScoped getDependsOnScoped() {",
- " return new DependsOnScoped(getScopedType());",
- " }",
- "",
- " private Provider<DependsOnScoped> getDependsOnScopedProvider() {",
- " Object local = dependsOnScopedProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " dependsOnScopedProvider = (Provider<DependsOnScoped>) local;",
- " }",
- " return (Provider<DependsOnScoped>) local;",
- " }",
- "",
- " @Override",
- " public NeedsProvider needsProvider() {",
- " return new NeedsProvider(getDependsOnScopedProvider());",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerSimpleComponent.this.getDependsOnScoped();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- "import dagger.internal.DoubleCheck;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<ScopedType> scopedTypeProvider;",
- " private Provider<DependsOnScoped> dependsOnScopedProvider;",
- "",
- " private DaggerSimpleComponent() {",
- " initialize();",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.scopedTypeProvider = DoubleCheck.provider(ScopedType_Factory.create());",
- " this.dependsOnScopedProvider = ",
- " DependsOnScoped_Factory.create(scopedTypeProvider);",
- " }",
- "",
- " @Override",
- " public NeedsProvider needsProvider() {",
- " return new NeedsProvider(dependsOnScopedProvider);",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {",
- " }",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(scopedType, dependsOnScoped, componentFile, needsProvider);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void scopedBinding_onlyUsedInSubcomponent() {
- JavaFileObject scopedType =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class ScopedType {",
- " @Inject ScopedType() {}",
- "}");
-
- JavaFileObject dependsOnScoped =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class DependsOnScoped {",
- " @Inject DependsOnScoped(ScopedType scoped) {}",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface SimpleComponent {",
- " Sub sub();",
- "}");
- JavaFileObject subcomponentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " DependsOnScoped dependsOnScoped();",
- "}");
-
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.MemoizedSentinel;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private volatile Object scopedType = new MemoizedSentinel();",
- "",
- " private DaggerSimpleComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private ScopedType getScopedType() {",
- " Object local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = scopedType;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new ScopedType();",
- " scopedType = DoubleCheck.reentrantCheck(scopedType, local);",
- " }",
- " }",
- " }",
- " return (ScopedType) local;",
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- "",
- " @Override",
- " public DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(DaggerSimpleComponent.this.getScopedType());",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerSimpleComponent",
- "package test;",
- "",
- "import dagger.internal.DoubleCheck;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerSimpleComponent implements SimpleComponent {",
- " private Provider<ScopedType> scopedTypeProvider;",
- "",
- " private DaggerSimpleComponent() {",
- " initialize();",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.scopedTypeProvider = DoubleCheck.provider(ScopedType_Factory.create());",
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public SimpleComponent build() {",
- " return new DaggerSimpleComponent();",
- " }",
- " }",
- "",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- "",
- " @Override",
- " public DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(",
- " DaggerSimpleComponent.this.scopedTypeProvider.get());",
- " }",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(scopedType, dependsOnScoped, componentFile, subcomponentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerSimpleComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/FrameworkFieldTest.java b/javatests/dagger/internal/codegen/FrameworkFieldTest.java
deleted file mode 100644
index cbc8c03..0000000
--- a/javatests/dagger/internal/codegen/FrameworkFieldTest.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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTOR;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
-import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-
-import com.google.testing.compile.CompilationRule;
-import com.squareup.javapoet.ClassName;
-import javax.inject.Inject;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test case for {@link FrameworkField}.
- */
-@RunWith(JUnit4.class)
-public class FrameworkFieldTest {
- @Rule public CompilationRule compilationRule = new CompilationRule();
-
- private ClassName xTypeName;
-
- @Before public void setUp() {
- xTypeName =
- ClassName.get(compilationRule.getElements().getTypeElement(X.class.getCanonicalName()));
- }
-
- @Test public void frameworkType() {
- assertThat(FrameworkField.create(PROVIDER, xTypeName, "test").type())
- .isEqualTo(providerOf(xTypeName));
- assertThat(FrameworkField.create(MEMBERS_INJECTOR, xTypeName, "test").type())
- .isEqualTo(membersInjectorOf(xTypeName));
- }
-
- @Test public void nameSuffix() {
- assertThat(FrameworkField.create(PROVIDER, xTypeName, "foo").name())
- .isEqualTo("fooProvider");
- assertThat(FrameworkField.create(PROVIDER, xTypeName, "fooProvider").name())
- .isEqualTo("fooProvider");
- }
-
- static final class X {
- @Inject X() {}
- }
-}
diff --git a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
deleted file mode 100644
index 3e6e3ad..0000000
--- a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
+++ /dev/null
@@ -1,48 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-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 org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Test case for {@link FrameworkTypeMapper}. */
-@RunWith(JUnit4.class)
-public class FrameworkTypeMapperTest {
- @Test public void forProvider() {
- FrameworkTypeMapper mapper = FrameworkTypeMapper.FOR_PROVIDER;
- assertThat(mapper.getFrameworkType(INSTANCE)).isEqualTo(FrameworkType.PROVIDER);
- assertThat(mapper.getFrameworkType(LAZY)).isEqualTo(FrameworkType.PROVIDER);
- assertThat(mapper.getFrameworkType(PROVIDER)).isEqualTo(FrameworkType.PROVIDER);
- }
-
- @Test public void forProducer() {
- FrameworkTypeMapper mapper = FrameworkTypeMapper.FOR_PRODUCER;
- assertThat(mapper.getFrameworkType(INSTANCE)).isEqualTo(FrameworkType.PRODUCER_NODE);
- assertThat(mapper.getFrameworkType(LAZY)).isEqualTo(FrameworkType.PROVIDER);
- assertThat(mapper.getFrameworkType(PROVIDER)).isEqualTo(FrameworkType.PROVIDER);
- assertThat(mapper.getFrameworkType(PRODUCER)).isEqualTo(FrameworkType.PRODUCER_NODE);
- assertThat(mapper.getFrameworkType(PRODUCED)).isEqualTo(FrameworkType.PRODUCER_NODE);
- }
-}
diff --git a/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java b/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java
deleted file mode 100644
index 944e307..0000000
--- a/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java
+++ /dev/null
@@ -1,478 +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 dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.endsWithMessage;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.regex.Pattern;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class FullBindingGraphValidationTest {
- 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);",
- " @Binds Number missingDependency(Integer i);",
- "}");
-
- // Make sure the error doesn't show other bindings or a dependency trace afterwards.
- private static final Pattern MODULE_WITH_ERRORS_MESSAGE =
- endsWithMessage(
- "[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() {
- Compilation compilation = daggerCompiler().compile(MODULE_WITH_ERRORS);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void moduleWithErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(MODULE_WITH_ERRORS);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_ERRORS)
- .onLineContaining("interface ModuleWithErrors");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void moduleWithErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(MODULE_WITH_ERRORS);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_ERRORS)
- .onLineContaining("interface ModuleWithErrors");
-
- assertThat(compilation).hadWarningCount(1);
- }
-
- private static final JavaFileObject INCLUDES_MODULE_WITH_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.IncludesModuleWithErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module(includes = ModuleWithErrors.class)",
- "interface IncludesModuleWithErrors {}");
-
- @Test
- public void includesModuleWithErrors_validationTypeNone() {
- Compilation compilation =
- daggerCompiler().compile(MODULE_WITH_ERRORS, INCLUDES_MODULE_WITH_ERRORS);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void includesModuleWithErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(MODULE_WITH_ERRORS, INCLUDES_MODULE_WITH_ERRORS);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_ERRORS)
- .onLineContaining("interface ModuleWithErrors");
-
- assertThat(compilation)
- .hadErrorContainingMatch("test.ModuleWithErrors has errors")
- .inFile(INCLUDES_MODULE_WITH_ERRORS)
- .onLineContaining("ModuleWithErrors.class");
-
- assertThat(compilation).hadErrorCount(2);
- }
-
- @Test
- public void includesModuleWithErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(MODULE_WITH_ERRORS, INCLUDES_MODULE_WITH_ERRORS);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_ERRORS)
- .onLineContaining("interface ModuleWithErrors");
-
- // TODO(b/130284666)
- assertThat(compilation)
- .hadWarningContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
- .inFile(INCLUDES_MODULE_WITH_ERRORS)
- .onLineContaining("interface IncludesModuleWithErrors");
-
- assertThat(compilation).hadWarningCount(2);
- }
-
- private static final JavaFileObject A_MODULE =
- JavaFileObjects.forSourceLines(
- "test.AModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface AModule {",
- " @Binds Object object(String string);",
- "}");
-
- private static final JavaFileObject COMBINED_WITH_A_MODULE_HAS_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.CombinedWithAModuleHasErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module(includes = AModule.class)",
- "interface CombinedWithAModuleHasErrors {",
- " @Binds Object object(Long l);",
- "}");
-
- // 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(
- "[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() {
- Compilation compilation = daggerCompiler().compile(A_MODULE, COMBINED_WITH_A_MODULE_HAS_ERRORS);
-
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void moduleIncludingModuleWithCombinedErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(A_MODULE, COMBINED_WITH_A_MODULE_HAS_ERRORS);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(COMBINED_WITH_A_MODULE_HAS_ERRORS_MESSAGE)
- .inFile(COMBINED_WITH_A_MODULE_HAS_ERRORS)
- .onLineContaining("interface CombinedWithAModuleHasErrors");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void moduleIncludingModuleWithCombinedErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(A_MODULE, COMBINED_WITH_A_MODULE_HAS_ERRORS);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(COMBINED_WITH_A_MODULE_HAS_ERRORS_MESSAGE)
- .inFile(COMBINED_WITH_A_MODULE_HAS_ERRORS)
- .onLineContaining("interface CombinedWithAModuleHasErrors");
-
- assertThat(compilation).hadWarningCount(1);
- }
-
- private static final JavaFileObject SUBCOMPONENT_WITH_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.SubcomponentWithErrors",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = AModule.class)",
- "interface SubcomponentWithErrors {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " @BindsInstance Builder object(Object object);",
- " SubcomponentWithErrors build();",
- " }",
- "}");
-
- // Make sure the error doesn't show other bindings or a dependency trace afterwards.
- private static final Pattern SUBCOMPONENT_WITH_ERRORS_MESSAGE =
- endsWithMessage(
- "[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() {
- Compilation compilation = daggerCompiler().compile(SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void subcomponentWithErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface SubcomponentWithErrors");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void subcomponentWithErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface SubcomponentWithErrors");
-
- assertThat(compilation).hadWarningCount(1);
- }
-
- private static final JavaFileObject MODULE_WITH_SUBCOMPONENT_WITH_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithSubcomponentWithErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module(subcomponents = SubcomponentWithErrors.class)",
- "interface ModuleWithSubcomponentWithErrors {}");
-
- @Test
- public void moduleWithSubcomponentWithErrors_validationTypeNone() {
- Compilation compilation =
- daggerCompiler()
- .compile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS, SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void moduleWithSubcomponentWithErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS, SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface ModuleWithSubcomponentWithErrors");
-
- // TODO(b/130283677)
- assertThat(compilation)
- .hadErrorContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface SubcomponentWithErrors");
-
- assertThat(compilation).hadErrorCount(2);
- }
-
- @Test
- public void moduleWithSubcomponentWithErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS, SUBCOMPONENT_WITH_ERRORS, A_MODULE);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface ModuleWithSubcomponentWithErrors");
-
- // TODO(b/130283677)
- assertThat(compilation)
- .hadWarningContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
- .inFile(SUBCOMPONENT_WITH_ERRORS)
- .onLineContaining("interface SubcomponentWithErrors");
-
- assertThat(compilation).hadWarningCount(2);
- }
-
- private static final JavaFileObject A_SUBCOMPONENT =
- JavaFileObjects.forSourceLines(
- "test.ASubcomponent",
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = AModule.class)",
- "interface ASubcomponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ASubcomponent build();",
- " }",
- "}");
-
- private static final JavaFileObject COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.CombinedWithASubcomponentHasErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module(subcomponents = ASubcomponent.class)",
- "interface CombinedWithASubcomponentHasErrors {",
- " @Binds Object object(Number number);",
- "}");
-
- // 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(
- "[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() {
- Compilation compilation =
- daggerCompiler().compile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS, A_SUBCOMPONENT, A_MODULE);
-
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void moduleWithSubcomponentWithCombinedErrors_validationTypeError() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS, A_SUBCOMPONENT, A_MODULE);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContainingMatch(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS_MESSAGE)
- .inFile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS)
- .onLineContaining("interface CombinedWithASubcomponentHasErrors");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void moduleWithSubcomponentWithCombinedErrors_validationTypeWarning() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
- .compile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS, A_SUBCOMPONENT, A_MODULE);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContainingMatch(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS_MESSAGE)
- .inFile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS)
- .onLineContaining("interface CombinedWithASubcomponentHasErrors");
-
- assertThat(compilation).hadWarningCount(1);
- }
-
- @Test
- public void bothAliasesDifferentValues() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- "-Adagger.moduleBindingValidation=NONE",
- "-Adagger.fullBindingGraphValidation=ERROR")
- .compile(MODULE_WITH_ERRORS);
-
- assertThat(compilation).failed();
-
- assertThat(compilation)
- .hadErrorContaining(
- "Only one of the equivalent options "
- + "(-Adagger.fullBindingGraphValidation, -Adagger.moduleBindingValidation)"
- + " should be used; prefer -Adagger.fullBindingGraphValidation");
-
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void bothAliasesSameValue() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- "-Adagger.moduleBindingValidation=NONE", "-Adagger.fullBindingGraphValidation=NONE")
- .compile(MODULE_WITH_ERRORS);
-
- assertThat(compilation).succeeded();
-
- assertThat(compilation)
- .hadWarningContaining(
- "Only one of the equivalent options "
- + "(-Adagger.fullBindingGraphValidation, -Adagger.moduleBindingValidation)"
- + " should be used; prefer -Adagger.fullBindingGraphValidation");
- }
-}
diff --git a/javatests/dagger/internal/codegen/GeneratedLines.java b/javatests/dagger/internal/codegen/GeneratedLines.java
deleted file mode 100644
index 2aa17ac..0000000
--- a/javatests/dagger/internal/codegen/GeneratedLines.java
+++ /dev/null
@@ -1,53 +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;
-
-import static dagger.internal.codegen.javapoet.CodeBlocks.stringLiteral;
-
-import com.squareup.javapoet.CodeBlock;
-
-/**
- * Common lines outputted during code generation.
- */
-public final class GeneratedLines {
- public static final String GENERATED_ANNOTATION =
- "@Generated("
- + "value = \"dagger.internal.codegen.ComponentProcessor\", "
- + "comments = \"https://dagger.dev\")";
-
- public static final String IMPORT_GENERATED_ANNOTATION =
- isBeforeJava9()
- ? "import javax.annotation.Generated;"
- : "import javax.annotation.processing.Generated;";
-
- static final String GENERATION_OPTIONS_ANNOTATION = "@GenerationOptions(fastInit = false)";
-
- private static boolean isBeforeJava9() {
- try {
- Class.forName("java.lang.Module");
- return false;
- } catch (ClassNotFoundException e) {
- 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/GeneratingProcessor.java b/javatests/dagger/internal/codegen/GeneratingProcessor.java
deleted file mode 100644
index 8e4e7b5..0000000
--- a/javatests/dagger/internal/codegen/GeneratingProcessor.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;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Set;
-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.TypeElement;
-
-/** A simple {@link Processor} that generates one source file. */
-final class GeneratingProcessor extends AbstractProcessor {
- private final String generatedClassName;
- private final String generatedSource;
- private boolean processed;
-
- GeneratingProcessor(String generatedClassName, String... source) {
- this.generatedClassName = generatedClassName;
- this.generatedSource = Joiner.on("\n").join(source);
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latestSupported();
- }
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of("*");
- }
-
- @Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- if (!processed) {
- processed = true;
- try (Writer writer =
- processingEnv.getFiler().createSourceFile(generatedClassName).openWriter()) {
- writer.append(generatedSource);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- return false;
- }
-}
diff --git a/javatests/dagger/internal/codegen/GenericMethodsTest.java b/javatests/dagger/internal/codegen/GenericMethodsTest.java
deleted file mode 100644
index cd4595e..0000000
--- a/javatests/dagger/internal/codegen/GenericMethodsTest.java
+++ /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.
- */
-
-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 class GenericMethodsTest {
- @Test
- public void parameterizedComponentMethods() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "import java.util.Set;",
- "",
- "@Component",
- "interface TestComponent {",
- " <T1> void injectTypeVariable(T1 type);",
- " <T2> MembersInjector<T2> membersInjector();",
- " <T3> Set<T3> setOfT();",
- " <UNUSED> TestComponent unused();",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cannot have type variables")
- .inFile(component)
- .onLineContaining("<T1>");
- assertThat(compilation)
- .hadErrorContaining("cannot have type variables")
- .inFile(component)
- .onLineContaining("<T2>");
- assertThat(compilation)
- .hadErrorContaining("cannot have type variables")
- .inFile(component)
- .onLineContaining("<T3>");
- assertThat(compilation)
- .hadErrorContaining("cannot have type variables")
- .inFile(component)
- .onLineContaining("<UNUSED>");
- }
-}
diff --git a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
deleted file mode 100644
index e6e9706..0000000
--- a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
+++ /dev/null
@@ -1,1410 +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;
-
-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 com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
-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.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)
-// TODO(gak): add tests for generation in the default package.
-public final class InjectConstructorFactoryGeneratorTest {
- private static final JavaFileObject QUALIFIER_A =
- JavaFileObjects.forSourceLines("test.QualifierA",
- "package test;",
- "",
- "import javax.inject.Qualifier;",
- "",
- "@Qualifier @interface QualifierA {}");
- private static final JavaFileObject QUALIFIER_B =
- JavaFileObjects.forSourceLines("test.QualifierB",
- "package test;",
- "",
- "import javax.inject.Qualifier;",
- "",
- "@Qualifier @interface QualifierB {}");
- private static final JavaFileObject SCOPE_A =
- JavaFileObjects.forSourceLines("test.ScopeA",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeA {}");
- private static final JavaFileObject SCOPE_B =
- JavaFileObjects.forSourceLines("test.ScopeB",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeB {}");
-
- @Test public void injectOnPrivateConstructor() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateConstructor",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class PrivateConstructor {",
- " @Inject private PrivateConstructor() {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private constructors")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void injectConstructorOnInnerClass() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class OuterClass {",
- " class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@Inject constructors are invalid on inner classes. "
- + "Did you mean to make the class static?")
- .inFile(file)
- .onLine(7);
- }
-
- @Test public void injectConstructorOnAbstractClass() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "abstract class AbstractClass {",
- " @Inject AbstractClass() {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Inject is nonsense on the constructor of an abstract class")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void injectConstructorOnGenericClass() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GenericClass<T> {",
- " @Inject GenericClass(T t) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
- " private final Provider<T> tProvider;",
- "",
- " public GenericClass_Factory(Provider<T> tProvider) {",
- " this.tProvider = tProvider;",
- " }",
- "",
- " @Override",
- " public GenericClass<T> get() {",
- " return new GenericClass<T>(tProvider.get());",
- " }",
- "",
- " public static <T> GenericClass_Factory<T> create(Provider<T> tProvider) {",
- " return new GenericClass_Factory<T>(tProvider);",
- " }",
- "",
- " public static <T> GenericClass<T> newInstance(T t) {",
- " return new GenericClass<T>(t);",
- " }",
- "}");
- assertAbout(javaSource()).that(file)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void fieldAndMethodGenerics() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GenericClass<A, B> {",
- " @Inject A a;",
- "",
- " @Inject GenericClass() {}",
- "",
- " @Inject void register(B b) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
- " private final Provider<A> aProvider;",
- " private final Provider<B> bProvider;",
- "",
- " public GenericClass_Factory(",
- " Provider<A> aProvider, Provider<B> bProvider) {",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " @Override",
- " public GenericClass<A, B> get() {",
- " GenericClass<A, B> instance = new GenericClass<A, B>();",
- " GenericClass_MembersInjector.injectA(instance, aProvider.get());",
- " GenericClass_MembersInjector.injectRegister(instance, bProvider.get());",
- " return instance;",
- " }",
- "",
- " public static <A, B> GenericClass_Factory<A, B> create(",
- " Provider<A> aProvider, Provider<B> bProvider) {",
- " return new GenericClass_Factory<A, B>(aProvider, bProvider);",
- " }",
- "",
- " public static <A, B> GenericClass<A, B> newInstance() {",
- " return new GenericClass<A, B>();",
- " }",
- "}");
- assertAbout(javaSource()).that(file)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void genericClassWithNoDependencies() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GenericClass<T> {",
- " @Inject GenericClass() {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- 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 new GenericClass<T>();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " public static <T> GenericClass_Factory<T> create() {",
- " return INSTANCE;",
- " }",
- "",
- " public static <T> GenericClass<T> newInstance() {",
- " return new GenericClass<T>();",
- " }",
- "}");
- assertAbout(javaSource()).that(file)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void twoGenericTypes() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GenericClass<A, B> {",
- " @Inject GenericClass(A a, B b) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
- " private final Provider<A> aProvider;",
- " private final Provider<B> bProvider;",
- "",
- " public GenericClass_Factory(Provider<A> aProvider, Provider<B> bProvider) {",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " @Override",
- " public GenericClass<A, B> get() {",
- " return new GenericClass<A, B>(aProvider.get(), bProvider.get());",
- " }",
- "",
- " public static <A, B> GenericClass_Factory<A, B> create(",
- " Provider<A> aProvider, Provider<B> bProvider) {",
- " return new GenericClass_Factory<A, B>(aProvider, bProvider);",
- " }",
- "",
- " public static <A, B> GenericClass<A, B> newInstance(A a, B b) {",
- " return new GenericClass<A, B>(a, b);",
- " }",
- "}");
- assertAbout(javaSource()).that(file)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void boundedGenerics() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import java.util.List;",
- "",
- "class GenericClass<A extends Number & Comparable<A>,",
- " B extends List<? extends String>,",
- " C extends List<? super String>> {",
- " @Inject GenericClass(A a, B b, C c) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import java.util.List;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class GenericClass_Factory<A extends Number & Comparable<A>,",
- " B extends List<? extends String>,",
- " C extends List<? super String>>",
- " implements Factory<GenericClass<A, B, C>> {",
- " private final Provider<A> aProvider;",
- " private final Provider<B> bProvider;",
- " private final Provider<C> cProvider;",
- "",
- " public GenericClass_Factory(Provider<A> aProvider,",
- " Provider<B> bProvider,",
- " Provider<C> cProvider) {",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " this.cProvider = cProvider;",
- " }",
- "",
- " @Override",
- " public GenericClass<A, B, C> get() {",
- " return new GenericClass<A, B, C>(",
- " aProvider.get(), bProvider.get(), cProvider.get());",
- " }",
- "",
- " public static <A extends Number & Comparable<A>,",
- " B extends List<? extends String>,",
- " C extends List<? super String>> GenericClass_Factory<A, B, C> create(",
- " Provider<A> aProvider, Provider<B> bProvider, Provider<C> cProvider) {",
- " return new GenericClass_Factory<A, B, C>(aProvider, bProvider, cProvider);",
- " }",
- "",
- " public static <",
- " A extends Number & Comparable<A>,",
- " B extends List<? extends String>,",
- " C extends List<? super String>>",
- " GenericClass<A, B, C> newInstance(A a, B b, C c) {",
- " return new GenericClass<A, B, C>(a, b, c);",
- " }",
- "}");
- assertAbout(javaSource()).that(file)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "import dagger.Lazy;",
- "",
- "class GenericClass<A, B> {",
- " @Inject GenericClass(A a, A a2, Provider<A> pa, @QualifierA A qa, Lazy<A> la, ",
- " String s, String s2, Provider<String> ps, ",
- " @QualifierA String qs, Lazy<String> ls,",
- " B b, B b2, Provider<B> pb, @QualifierA B qb, Lazy<B> lb) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_Factory",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class GenericClass_Factory<A, B>",
- " implements Factory<GenericClass<A, B>> {",
- " private final Provider<A> aAndA2AndPaAndLaProvider;",
- " private final Provider<A> qaProvider;",
- " private final Provider<String> sAndS2AndPsAndLsProvider;",
- " private final Provider<String> qsProvider;",
- " private final Provider<B> bAndB2AndPbAndLbProvider;",
- " private final Provider<B> qbProvider;",
- "",
- " public GenericClass_Factory(Provider<A> aAndA2AndPaAndLaProvider,",
- " Provider<A> qaProvider,",
- " Provider<String> sAndS2AndPsAndLsProvider,",
- " Provider<String> qsProvider,",
- " Provider<B> bAndB2AndPbAndLbProvider,",
- " Provider<B> qbProvider) {",
- " this.aAndA2AndPaAndLaProvider = aAndA2AndPaAndLaProvider;",
- " this.qaProvider = qaProvider;",
- " this.sAndS2AndPsAndLsProvider = sAndS2AndPsAndLsProvider;",
- " this.qsProvider = qsProvider;",
- " this.bAndB2AndPbAndLbProvider = bAndB2AndPbAndLbProvider;",
- " this.qbProvider = qbProvider;",
- " }",
- "",
- " @Override",
- " public GenericClass<A, B> get() {",
- " 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> aAndA2AndPaAndLaProvider,",
- " Provider<A> qaProvider,",
- " Provider<String> sAndS2AndPsAndLsProvider,",
- " Provider<String> qsProvider,",
- " Provider<B> bAndB2AndPbAndLbProvider,",
- " Provider<B> qbProvider) {",
- " return new GenericClass_Factory<A, B>(",
- " aAndA2AndPaAndLaProvider,",
- " qaProvider,",
- " sAndS2AndPsAndLsProvider,",
- " qsProvider,",
- " bAndB2AndPbAndLbProvider,",
- " qbProvider);",
- " }",
- "",
- " public static <A, B> GenericClass<A, B> newInstance(",
- " A a,",
- " A a2,",
- " Provider<A> pa,",
- " A qa,",
- " Lazy<A> la,",
- " String s,",
- " String s2,",
- " Provider<String> ps,",
- " String qs,",
- " Lazy<String> ls,",
- " B b,",
- " B b2,",
- " Provider<B> pb,",
- " B qb,",
- " Lazy<B> lb) {",
- " return new GenericClass<A, B>(",
- " a, a2, pa, qa, la, s, s2, ps, qs, ls, b, b2, pb, qb, lb);",
- " }",
- "}");
- assertAbout(javaSources()).that(ImmutableList.of(file, QUALIFIER_A))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void multipleInjectConstructors() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.TooManyInjectConstructors",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class TooManyInjectConstructors {",
- " @Inject TooManyInjectConstructors() {}",
- " TooManyInjectConstructors(int i) {}",
- " @Inject TooManyInjectConstructors(String s) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Types may only contain one @Inject constructor")
- .inFile(file)
- .onLine(6);
- assertThat(compilation)
- .hadErrorContaining("Types may only contain one @Inject constructor")
- .inFile(file)
- .onLine(8);
- }
-
- @Test public void multipleQualifiersOnInjectConstructorParameter() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierConstructorParam",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class MultipleQualifierConstructorParam {",
- " @Inject MultipleQualifierConstructorParam(@QualifierA @QualifierB String s) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- // for whatever reason, javac only reports the error once on the constructor
- assertThat(compilation)
- .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void injectConstructorOnClassWithMultipleScopes() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@ScopeA @ScopeB class MultipleScopeClass {",
- " @Inject MultipleScopeClass() {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file, SCOPE_A, SCOPE_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("A single binding may not declare more than one @Scope")
- .inFile(file)
- .onLine(5)
- .atColumn(1);
- assertThat(compilation)
- .hadErrorContaining("A single binding may not declare more than one @Scope")
- .inFile(file)
- .onLine(5)
- .atColumn(9);
- }
-
- @Test public void injectConstructorWithQualifier() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleScopeClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class MultipleScopeClass {",
- " @Inject",
- " @QualifierA",
- " @QualifierB",
- " MultipleScopeClass() {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Qualifier annotations are not allowed on @Inject constructors")
- .inFile(file)
- .onLine(7);
- assertThat(compilation)
- .hadErrorContaining("@Qualifier annotations are not allowed on @Inject constructors")
- .inFile(file)
- .onLine(8);
- }
-
- @Test public void injectConstructorWithCheckedExceptionsError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.CheckedExceptionClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class CheckedExceptionClass {",
- " @Inject CheckedExceptionClass() throws Exception {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support checked exceptions on @Inject constructors")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void injectConstructorWithCheckedExceptionsWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.CheckedExceptionClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class CheckedExceptionClass {",
- " @Inject CheckedExceptionClass() throws Exception {}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining("Dagger does not support checked exceptions on @Inject constructors")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateInjectClassError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(7);
- }
-
- @Test public void privateInjectClassWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(7);
- }
-
- @Test public void nestedInPrivateInjectClassError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class MiddleClass {",
- " static final class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(8);
- }
-
- @Test public void nestedInPrivateInjectClassWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class MiddleClass {",
- " static final class InnerClass {",
- " @Inject InnerClass() {}",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(8);
- }
-
- @Test public void finalInjectField() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.FinalInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FinalInjectField {",
- " @Inject final String s;",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Inject fields may not be final")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateInjectFieldError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class PrivateInjectField {",
- " @Inject private String s;",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private fields")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateInjectFieldWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class PrivateInjectField {",
- " @Inject private String s;",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
- }
-
- @Test public void staticInjectFieldError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class StaticInjectField {",
- " @Inject static String s;",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static fields")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void staticInjectFieldWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class StaticInjectField {",
- " @Inject static String s;",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
- }
-
- @Test public void multipleQualifiersOnField() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierInjectField",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class MultipleQualifierInjectField {",
- " @Inject @QualifierA @QualifierB String s;",
- "}");
- Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
- .inFile(file)
- .onLine(6)
- .atColumn(11);
- assertThat(compilation)
- .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
- .inFile(file)
- .onLine(6)
- .atColumn(23);
- }
-
- @Test public void abstractInjectMethod() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.AbstractInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "abstract class AbstractInjectMethod {",
- " @Inject abstract void method();",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Methods with @Inject may not be abstract")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateInjectMethodError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class PrivateInjectMethod {",
- " @Inject private void method(){}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private methods")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateInjectMethodWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.PrivateInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class PrivateInjectMethod {",
- " @Inject private void method(){}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
- }
-
- @Test public void staticInjectMethodError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class StaticInjectMethod {",
- " @Inject static void method(){}",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static methods")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void staticInjectMethodWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.StaticInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class StaticInjectMethod {",
- " @Inject static void method(){}",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
- assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
- }
-
- @Test public void genericInjectMethod() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericInjectMethod",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class AbstractInjectMethod {",
- " @Inject <T> void method();",
- "}");
- Compilation compilation = daggerCompiler().compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Methods with @Inject may not declare type parameters")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void multipleQualifiersOnInjectMethodParameter() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.MultipleQualifierMethodParam",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class MultipleQualifierMethodParam {",
- " @Inject void method(@QualifierA @QualifierB String s) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(file, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("A single dependency request may not use more than one @Qualifier")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void injectConstructorDependsOnProduced() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Produced;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(Produced<String> str) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Produced may only be injected in @Produces methods");
- }
-
- @Test public void injectConstructorDependsOnProducer() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Producer;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(Producer<String> str) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Producer may only be injected in @Produces methods");
- }
-
- @Test public void injectFieldDependsOnProduced() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Produced;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject Produced<String> str;",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Produced may only be injected in @Produces methods");
- }
-
- @Test public void injectFieldDependsOnProducer() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Producer;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject Producer<String> str;",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Producer may only be injected in @Produces methods");
- }
-
- @Test public void injectMethodDependsOnProduced() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Produced;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject void inject(Produced<String> str) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Produced may only be injected in @Produces methods");
- }
-
- @Test public void injectMethodDependsOnProducer() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import dagger.producers.Producer;",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject void inject(Producer<String> str) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(aFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Producer may only be injected in @Produces methods");
- }
-
- @Test public void injectConstructor() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class InjectConstructor {",
- " @Inject InjectConstructor(String s) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.InjectConstructor_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectConstructor_Factory ",
- " implements Factory<InjectConstructor> {",
- "",
- " private final Provider<String> sProvider;",
- "",
- " public InjectConstructor_Factory(Provider<String> sProvider) {",
- " this.sProvider = sProvider;",
- " }",
- "",
- " @Override public InjectConstructor get() {",
- " return new InjectConstructor(sProvider.get());",
- " }",
- "",
- " public static InjectConstructor_Factory create(Provider<String> sProvider) {",
- " return new InjectConstructor_Factory(sProvider);",
- " }",
- "",
- " public static InjectConstructor newInstance(String s) {",
- " return new InjectConstructor(s);",
- " }",
- "}");
- assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test public void injectConstructorAndMembersInjection() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class AllInjections {",
- " @Inject String s;",
- " @Inject AllInjections(String s) {}",
- " @Inject void s(String s) {}",
- "}");
- JavaFileObject expectedFactory =
- JavaFileObjects.forSourceLines(
- "test.AllInjections_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class AllInjections_Factory implements Factory<AllInjections> {",
- " private final Provider<String> sProvider;",
- "",
- " public AllInjections_Factory(Provider<String> sProvider) {",
- " this.sProvider = sProvider;",
- " }",
- "",
- " @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) {",
- " return new AllInjections_Factory(sProvider);",
- " }",
- "",
- " public static AllInjections newInstance(String s) {",
- " return new AllInjections(s);",
- " }",
- "}");
- assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expectedFactory);
- }
-
- @Test
- public void wildcardDependency() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
- "package test;",
- "",
- "import java.util.List;",
- "import javax.inject.Inject;",
- "",
- "class InjectConstructor {",
- " @Inject InjectConstructor(List<?> objects) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.InjectConstructor_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import java.util.List;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectConstructor_Factory ",
- " implements Factory<InjectConstructor> {",
- "",
- " private final Provider<List<?>> objectsProvider;",
- "",
- " public InjectConstructor_Factory(Provider<List<?>> objectsProvider) {",
- " this.objectsProvider = objectsProvider;",
- " }",
- "",
- " @Override public InjectConstructor get() {",
- " return new InjectConstructor(objectsProvider.get());",
- " }",
- "",
- " public static InjectConstructor_Factory create(",
- " Provider<List<?>> objectsProvider) {",
- " return new InjectConstructor_Factory(objectsProvider);",
- " }",
- "",
- " public static InjectConstructor newInstance(List<?> objects) {",
- " return new InjectConstructor(objects);",
- " }",
- "}");
- assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test
- public void basicNameCollision() {
- JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Factory",
- "package other.pkg;",
- "",
- "public class Factory {}");
- JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import other.pkg.Factory;",
- "",
- "class InjectConstructor {",
- " @Inject InjectConstructor(Factory factory) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.InjectConstructor_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectConstructor_Factory ",
- " implements Factory<InjectConstructor> {",
- "",
- " private final Provider<other.pkg.Factory> factoryProvider;",
- "",
- " public InjectConstructor_Factory(Provider<other.pkg.Factory> factoryProvider) {",
- " this.factoryProvider = factoryProvider;",
- " }",
- "",
- " @Override public InjectConstructor get() {",
- " return new InjectConstructor(factoryProvider.get());",
- " }",
- "",
- " public static InjectConstructor_Factory create(",
- " Provider<other.pkg.Factory> factoryProvider) {",
- " return new InjectConstructor_Factory(factoryProvider);",
- " }",
- "",
- " public static InjectConstructor newInstance(",
- " other.pkg.Factory factory) {",
- " return new InjectConstructor(factory);",
- " }",
- "}");
- assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test
- public void nestedNameCollision() {
- JavaFileObject factoryFile = JavaFileObjects.forSourceLines("other.pkg.Outer",
- "package other.pkg;",
- "",
- "public class Outer {",
- " public class Factory {}",
- "}");
- JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import other.pkg.Outer;",
- "",
- "class InjectConstructor {",
- " @Inject InjectConstructor(Outer.Factory factory) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.InjectConstructor_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "import other.pkg.Outer;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectConstructor_Factory ",
- " implements Factory<InjectConstructor> {",
- "",
- " private final Provider<Outer.Factory> factoryProvider;",
- "",
- " public InjectConstructor_Factory(Provider<Outer.Factory> factoryProvider) {",
- " this.factoryProvider = factoryProvider;",
- " }",
- "",
- " @Override public InjectConstructor get() {",
- " return new InjectConstructor(factoryProvider.get());",
- " }",
- "",
- " public static InjectConstructor_Factory create(",
- " Provider<Outer.Factory> factoryProvider) {",
- " return new InjectConstructor_Factory(factoryProvider);",
- " }",
- "",
- " public static InjectConstructor newInstance(",
- " Outer.Factory factory) {",
- " return new InjectConstructor(factory);",
- " }",
- "}");
- assertAbout(javaSources()).that(ImmutableList.of(factoryFile, file))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test
- public void samePackageNameCollision() {
- JavaFileObject samePackageInterface = JavaFileObjects.forSourceLines("test.CommonName",
- "package test;",
- "",
- "public interface CommonName {}");
- JavaFileObject differentPackageInterface = JavaFileObjects.forSourceLines(
- "other.pkg.CommonName",
- "package other.pkg;",
- "",
- "public interface CommonName {}");
- JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class InjectConstructor implements CommonName {",
- " @Inject InjectConstructor(other.pkg.CommonName otherPackage, CommonName samePackage) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.InjectConstructor_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectConstructor_Factory ",
- " implements Factory<InjectConstructor> {",
- "",
- " private final Provider<other.pkg.CommonName> otherPackageProvider;",
- " private final Provider<CommonName> samePackageProvider;",
- "",
- " public InjectConstructor_Factory(",
- " Provider<other.pkg.CommonName> otherPackageProvider,",
- " Provider<CommonName> samePackageProvider) {",
- " this.otherPackageProvider = otherPackageProvider;",
- " this.samePackageProvider = samePackageProvider;",
- " }",
- "",
- " @Override public InjectConstructor get() {",
- " return new InjectConstructor(",
- " otherPackageProvider.get(), samePackageProvider.get());",
- " }",
- "",
- " public static InjectConstructor_Factory create(",
- " Provider<other.pkg.CommonName> otherPackageProvider,",
- " Provider<CommonName> samePackageProvider) {",
- " return new InjectConstructor_Factory(otherPackageProvider, samePackageProvider);",
- " }",
- "",
- " public static InjectConstructor newInstance(",
- " other.pkg.CommonName otherPackage, CommonName samePackage) {",
- " return new InjectConstructor(otherPackage, samePackage);",
- " }",
- "}");
- assertAbout(javaSources())
- .that(ImmutableList.of(samePackageInterface, differentPackageInterface, file))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(expected);
- }
-
- @Test
- public void noDeps() {
- JavaFileObject simpleType = JavaFileObjects.forSourceLines("test.SimpleType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class SimpleType {",
- " @Inject SimpleType() {}",
- "}");
- JavaFileObject factory =
- JavaFileObjects.forSourceLines(
- "test.SimpleType_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class SimpleType_Factory implements Factory<SimpleType> {",
- " private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();",
- "",
- " @Override public SimpleType get() {",
- " return new SimpleType();",
- " }",
- "",
- " public static SimpleType_Factory create() {",
- " return INSTANCE;",
- " }",
- "",
- " public static SimpleType newInstance() {",
- " return new SimpleType();",
- " }",
- "}");
- assertAbout(javaSource())
- .that(simpleType)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factory);
- }
-
- @Test public void simpleComponentWithNesting() {
- JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines("test.OuterType",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "",
- "final class OuterType {",
- " static class A {",
- " @Inject A() {}",
- " }",
- " static class B {",
- " @Inject A a;",
- " }",
- "}");
- JavaFileObject aFactory =
- JavaFileObjects.forSourceLines(
- "test.OuterType_A_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- 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 new OuterType.A();",
- " }",
- "",
- " public static OuterType_A_Factory create() {",
- " return INSTANCE;",
- " }",
- "",
- " public static OuterType.A newInstance() {",
- " return new OuterType.A();",
- " }",
- "}");
- assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(aFactory);
- }
-}
diff --git a/javatests/dagger/internal/codegen/JavaFileBuilder.java b/javatests/dagger/internal/codegen/JavaFileBuilder.java
deleted file mode 100644
index f682b0c..0000000
--- a/javatests/dagger/internal/codegen/JavaFileBuilder.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;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import javax.tools.JavaFileObject;
-
-/**
- * A fluent API to build a {@link JavaFileObject} appropriate for a current set of settings, such as
- * compiler mode.
- *
- * <p>After creating a builder, you can add lines to the file. Call {@link #addLines(String...)} to
- * add lines irrespective of the settings. If you want to add different lines for different possible
- * settings, call {@link #addLinesIf(Object, String...)} to add those lines only if the given
- * setting has been added via {@link #withSetting(Object)} or {@link #withSettings(Object...)}.
- */
-final class JavaFileBuilder {
- private final String qualifiedName;
- private final Set<Object> settings = new HashSet<>();
-
- private final ImmutableList.Builder<String> sourceLines = ImmutableList.builder();
-
- /** Creates a builder for a file whose top level type has a given qualified name. */
- JavaFileBuilder(String qualifiedName) {
- checkArgument(!qualifiedName.isEmpty());
- this.qualifiedName = qualifiedName;
- }
-
- // TODO(cgdecker): Get rid of the special constructor/method for CompilerMode
-
- /** Creates a builder for a file whose top level type has a given qualified name. */
- JavaFileBuilder(CompilerMode compilerMode, String qualifiedName) {
- this(qualifiedName);
- settings.add(compilerMode);
- }
-
- /** Adds the given setting as one that code should be generated for. */
- JavaFileBuilder withSetting(Object setting) {
- this.settings.add(setting);
- return this;
- }
-
- /** Adds the given settings as one that code should be generated for. */
- JavaFileBuilder withSettings(Object s1, Object s2, Object... more) {
- settings.add(s1);
- settings.add(s2);
- Collections.addAll(settings, more);
- return this;
- }
-
- /** Adds lines no matter what the {@link CompilerMode} is. */
- JavaFileBuilder addLines(String... lines) {
- sourceLines.add(lines);
- return this;
- }
-
- /** Adds lines if in the given mode. */
- JavaFileBuilder addLinesIn(CompilerMode mode, String... lines) {
- return addLinesIf(mode, lines);
- }
-
- /** Adds lines if in the given setting is set. */
- JavaFileBuilder addLinesIf(Object setting, String... lines) {
- if (settings.contains(setting)) {
- sourceLines.add(lines);
- }
- return this;
- }
-
- /** Builds the {@link JavaFileObject}. */
- JavaFileObject build() {
- return JavaFileObjects.forSourceLines(qualifiedName, sourceLines.build());
- }
-}
diff --git a/javatests/dagger/internal/codegen/KeyFactoryTest.java b/javatests/dagger/internal/codegen/KeyFactoryTest.java
deleted file mode 100644
index d526ec9..0000000
--- a/javatests/dagger/internal/codegen/KeyFactoryTest.java
+++ /dev/null
@@ -1,332 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.testing.compile.CompilationRule;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.Key.MultibindingContributionIdentifier;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.lang.annotation.Retention;
-import java.util.Set;
-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;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link Key}.
- */
-@RunWith(JUnit4.class)
-public class KeyFactoryTest {
- @Rule public CompilationRule compilationRule = new CompilationRule();
-
- private DaggerElements elements;
- private DaggerTypes types;
- private KeyFactory keyFactory;
-
- @Before public void setUp() {
- 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() {
- TypeElement typeElement =
- compilationRule.getElements().getTypeElement(InjectedClass.class.getCanonicalName());
- ExecutableElement constructor =
- Iterables.getOnlyElement(ElementFilter.constructorsIn(typeElement.getEnclosedElements()));
- Key key =
- keyFactory.forInjectConstructorWithResolvedType(constructor.getEnclosingElement().asType());
- assertThat(key).isEqualTo(Key.builder(typeElement.asType()).build());
- assertThat(key.toString()).isEqualTo("dagger.internal.codegen.KeyFactoryTest.InjectedClass");
- }
-
- static final class InjectedClass {
- @SuppressWarnings("unused")
- @Inject InjectedClass(String s, int i) {}
- }
-
- @Test public void forProvidesMethod() {
- TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeElement moduleElement =
- elements.getTypeElement(ProvidesMethodModule.class.getCanonicalName());
- ExecutableElement providesMethod =
- Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
- Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(stringType).build());
- assertThat(key.toString()).isEqualTo("java.lang.String");
- }
-
- @Module
- static final class ProvidesMethodModule {
- @Provides String provideString() {
- throw new UnsupportedOperationException();
- }
- }
-
- @Test public void forProvidesMethod_qualified() {
- TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeElement qualifierElement =
- elements.getTypeElement(TestQualifier.class.getCanonicalName());
- TypeElement moduleElement =
- elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
- ExecutableElement providesMethod =
- Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
- Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(MoreTypes.equivalence().wrap(key.qualifier().get().getAnnotationType()))
- .isEqualTo(MoreTypes.equivalence().wrap(qualifierElement.asType()));
- assertThat(MoreTypes.equivalence().wrap(key.type()))
- .isEqualTo(MoreTypes.equivalence().wrap(stringType));
- assertThat(key.toString())
- .isEqualTo(
- "@dagger.internal.codegen.KeyFactoryTest.TestQualifier({"
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=1, value=\"value a\"), "
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=2, value=\"value b\"), "
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=3145, value=\"default\")"
- + "}) java.lang.String");
- }
-
- @Test public void qualifiedKeyEquivalents() {
- TypeElement moduleElement =
- elements.getTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
- ExecutableElement providesMethod =
- Iterables.getOnlyElement(ElementFilter.methodsIn(moduleElement.getEnclosedElements()));
- Key provisionKey = keyFactory.forProvidesMethod(providesMethod, moduleElement);
-
- TypeMirror type = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeElement injectableElement =
- elements.getTypeElement(QualifiedFieldHolder.class.getCanonicalName());
- Element injectionField =
- Iterables.getOnlyElement(ElementFilter.fieldsIn(injectableElement.getEnclosedElements()));
- AnnotationMirror qualifier = Iterables.getOnlyElement(injectionField.getAnnotationMirrors());
- Key injectionKey = Key.builder(type).qualifier(qualifier).build();
-
- assertThat(provisionKey).isEqualTo(injectionKey);
- assertThat(injectionKey.toString())
- .isEqualTo(
- "@dagger.internal.codegen.KeyFactoryTest.TestQualifier({"
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=1, value=\"value a\"), "
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=2, value=\"value b\"), "
- + "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
- + "param1=3145, value=\"default\")"
- + "}) java.lang.String");
- }
-
- @Module
- static final class QualifiedProvidesMethodModule {
- @Provides
- @TestQualifier({
- @InnerAnnotation(value = "value a", param1 = 1),
- // please note the order of 'param' and 'value' is inverse
- @InnerAnnotation(param1 = 2, value = "value b"),
- @InnerAnnotation()
- })
- static String provideQualifiedString() {
- throw new UnsupportedOperationException();
- }
- }
-
- static final class QualifiedFieldHolder {
- @TestQualifier({
- @InnerAnnotation(value = "value a", param1 = 1),
- // please note the order of 'param' and 'value' is inverse
- @InnerAnnotation(param1 = 2, value = "value b"),
- @InnerAnnotation()
- })
- String aString;
- }
-
- @Retention(RUNTIME)
- @Qualifier
- @interface TestQualifier {
- InnerAnnotation[] value();
- }
-
- @interface InnerAnnotation {
- int param1() default 3145;
-
- String value() default "default";
- }
-
- @Test public void forProvidesMethod_sets() {
- TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
- TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
- TypeElement moduleElement =
- elements.getTypeElement(SetProvidesMethodsModule.class.getCanonicalName());
- for (ExecutableElement providesMethod
- : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
- Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(key)
- .isEqualTo(
- Key.builder(setOfStringsType)
- .multibindingContributionIdentifier(
- new MultibindingContributionIdentifier(providesMethod, moduleElement))
- .build());
- assertThat(key.toString())
- .isEqualTo(
- String.format(
- "java.util.Set<java.lang.String> "
- + "dagger.internal.codegen.KeyFactoryTest.SetProvidesMethodsModule#%s",
- providesMethod.getSimpleName()));
- }
- }
-
- @Module
- static final class SetProvidesMethodsModule {
- @Provides @IntoSet String provideString() {
- throw new UnsupportedOperationException();
- }
-
- @Provides @ElementsIntoSet Set<String> provideStrings() {
- throw new UnsupportedOperationException();
- }
- }
-
- @Module
- static final class PrimitiveTypes {
- @Provides int foo() {
- return 0;
- }
- }
-
- @Module
- static final class BoxedPrimitiveTypes {
- @Provides Integer foo() {
- return 0;
- }
- }
-
- @Test public void primitiveKeysMatchBoxedKeys() {
- TypeElement primitiveHolder = elements.getTypeElement(PrimitiveTypes.class.getCanonicalName());
- ExecutableElement intMethod =
- Iterables.getOnlyElement(ElementFilter.methodsIn(primitiveHolder.getEnclosedElements()));
- TypeElement boxedPrimitiveHolder =
- elements.getTypeElement(BoxedPrimitiveTypes.class.getCanonicalName());
- ExecutableElement integerMethod = Iterables.getOnlyElement(
- ElementFilter.methodsIn(boxedPrimitiveHolder.getEnclosedElements()));
-
- // TODO(cgruber): Truth subject for TypeMirror and TypeElement
- TypeMirror intType = intMethod.getReturnType();
- assertThat(intType.getKind().isPrimitive()).isTrue();
- TypeMirror integerType = integerMethod.getReturnType();
- assertThat(integerType.getKind().isPrimitive()).isFalse();
- assertWithMessage("type equality").that(types.isSameType(intType, integerType)).isFalse();
- Key intKey = keyFactory.forProvidesMethod(intMethod, primitiveHolder);
- Key integerKey = keyFactory.forProvidesMethod(integerMethod, boxedPrimitiveHolder);
- assertThat(intKey).isEqualTo(integerKey);
- assertThat(intKey.toString()).isEqualTo("java.lang.Integer");
- assertThat(integerKey.toString()).isEqualTo("java.lang.Integer");
- }
-
- @Test public void forProducesMethod() {
- TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeElement moduleElement =
- elements.getTypeElement(ProducesMethodsModule.class.getCanonicalName());
- for (ExecutableElement producesMethod
- : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
- Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(stringType).build());
- assertThat(key.toString()).isEqualTo("java.lang.String");
- }
- }
-
- @ProducerModule
- static final class ProducesMethodsModule {
- @Produces String produceString() {
- throw new UnsupportedOperationException();
- }
-
- @Produces ListenableFuture<String> produceFutureString() {
- throw new UnsupportedOperationException();
- }
- }
-
- @Test public void forProducesMethod_sets() {
- TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
- TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
- TypeMirror setOfStringsType = types.getDeclaredType(setElement, stringType);
- TypeElement moduleElement =
- elements.getTypeElement(SetProducesMethodsModule.class.getCanonicalName());
- for (ExecutableElement producesMethod
- : ElementFilter.methodsIn(moduleElement.getEnclosedElements())) {
- Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
- assertThat(key)
- .isEqualTo(
- Key.builder(setOfStringsType)
- .multibindingContributionIdentifier(
- new MultibindingContributionIdentifier(producesMethod, moduleElement))
- .build());
- assertThat(key.toString())
- .isEqualTo(
- String.format(
- "java.util.Set<java.lang.String> "
- + "dagger.internal.codegen.KeyFactoryTest.SetProducesMethodsModule#%s",
- producesMethod.getSimpleName()));
- }
- }
-
- @ProducerModule
- static final class SetProducesMethodsModule {
- @Produces @IntoSet String produceString() {
- throw new UnsupportedOperationException();
- }
-
- @Produces @IntoSet ListenableFuture<String> produceFutureString() {
- throw new UnsupportedOperationException();
- }
-
- @Produces @ElementsIntoSet Set<String> produceStrings() {
- throw new UnsupportedOperationException();
- }
-
- @Produces @ElementsIntoSet
- ListenableFuture<Set<String>> produceFutureStrings() {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
deleted file mode 100644
index ad48712..0000000
--- a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
+++ /dev/null
@@ -1,1101 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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;
-import java.util.Collection;
-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 MapBindingComponentProcessorTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public MapBindingComponentProcessorTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void mapBindingsWithEnumKey() {
- JavaFileObject mapModuleOneFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleOne",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleOne {",
- " @Provides @IntoMap @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
- " return new AdminHandler();",
- " }",
- "}");
- JavaFileObject mapModuleTwoFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleTwo",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleTwo {",
- " @Provides @IntoMap @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
- " return new LoginHandler();",
- " }",
- "}");
- JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
- "package test;",
- "import dagger.MapKey;",
- "import java.lang.annotation.Retention;",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "@MapKey(unwrapValue = true)",
- "@Retention(RUNTIME)",
- "public @interface PathKey {",
- " PathEnum value();",
- "}");
- JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
- "package test;",
- "",
- "public enum PathEnum {",
- " ADMIN,",
- " LOGIN;",
- "}");
-
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
- "interface TestComponent {",
- " Provider<Map<PathEnum, Provider<Handler>>> dispatcher();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<PathEnum, Provider<Handler>>>",
- " mapOfPathEnumAndProviderOfHandlerProvider;",
- "",
- " private Provider<Handler> getProvideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> getProvideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<PathEnum, Provider<Handler>>",
- " getMapOfPathEnumAndProviderOfHandler() {",
- " return ImmutableMap.<PathEnum, Provider<Handler>>of(",
- " PathEnum.ADMIN, getProvideAdminHandlerProvider(),",
- " PathEnum.LOGIN, getProvideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfPathEnumAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfPathEnumAndProviderOfHandlerProvider =",
- " (Provider<Map<PathEnum, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<PathEnum, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .getMapOfPathEnumAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<PathEnum, Provider<Handler>>>",
- " mapOfPathEnumAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfPathEnumAndProviderOfHandlerProvider =",
- " MapProviderFactory.<PathEnum, Handler>builder(2)",
- " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
- " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
- " return mapOfPathEnumAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- mapModuleOneFile,
- mapModuleTwoFile,
- enumKeyFile,
- pathEnumFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void mapBindingsWithInaccessibleKeys() {
- JavaFileObject mapKeys =
- JavaFileObjects.forSourceLines(
- "mapkeys.MapKeys",
- "package mapkeys;",
- "",
- "import dagger.MapKey;",
- "import dagger.multibindings.ClassKey;",
- "",
- "public class MapKeys {",
- " @MapKey(unwrapValue = false)",
- " public @interface ComplexKey {",
- " Class<?>[] manyClasses();",
- " Class<?> oneClass();",
- " ClassKey annotation();",
- " }",
- "",
- " @MapKey",
- " @interface EnumKey {",
- " PackagePrivateEnum value();",
- " }",
- "",
- " enum PackagePrivateEnum { INACCESSIBLE }",
- "",
- " interface Inaccessible {}",
- "}");
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "mapkeys.MapModule",
- "package mapkeys;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ClassKey;",
- "import dagger.multibindings.IntoMap;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Module",
- "public interface MapModule {",
- " @Provides @IntoMap @ClassKey(MapKeys.Inaccessible.class)",
- " static int classKey() { return 1; }",
- "",
- " @Provides @IntoMap @MapKeys.EnumKey(MapKeys.PackagePrivateEnum.INACCESSIBLE)",
- " static int enumKey() { return 1; }",
- "",
- " @Binds Object bindInaccessibleEnumMapToAccessibleTypeForComponent(",
- " Map<MapKeys.PackagePrivateEnum, Integer> map);",
- "",
- " @Provides @IntoMap",
- " @MapKeys.ComplexKey(",
- " manyClasses = {java.lang.Object.class, java.lang.String.class},",
- " oneClass = MapKeys.Inaccessible.class,",
- " annotation = @ClassKey(java.lang.Object.class)",
- " )",
- " static int complexKeyWithInaccessibleValue() { return 1; }",
- "",
- " @Provides @IntoMap",
- " @MapKeys.ComplexKey(",
- " manyClasses = {MapKeys.Inaccessible.class, java.lang.String.class},",
- " oneClass = java.lang.String.class,",
- " annotation = @ClassKey(java.lang.Object.class)",
- " )",
- " static int complexKeyWithInaccessibleArrayValue() { return 1; }",
- "",
- " @Provides @IntoMap",
- " @MapKeys.ComplexKey(",
- " manyClasses = {java.lang.String.class},",
- " oneClass = java.lang.String.class,",
- " annotation = @ClassKey(MapKeys.Inaccessible.class)",
- " )",
- " static int complexKeyWithInaccessibleAnnotationValue() { return 1; }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "import mapkeys.MapKeys;",
- "import mapkeys.MapModule;",
- "",
- "@Component(modules = MapModule.class)",
- "interface TestComponent {",
- " Map<Class<?>, Integer> classKey();",
- " Provider<Map<Class<?>, Integer>> classKeyProvider();",
- "",
- " Object inaccessibleEnum();",
- " Provider<Object> inaccessibleEnumProvider();",
- "",
- " Map<MapKeys.ComplexKey, Integer> complexKey();",
- " Provider<Map<MapKeys.ComplexKey, Integer>> complexKeyProvider();",
- "}");
- Compilation compilation = daggerCompiler().compile(mapKeys, moduleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Map<Class<?>, Integer>> mapOfClassOfAndIntegerProvider;",
- "",
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider mapOfPackagePrivateEnumAndIntegerProvider;",
- "",
- " private Provider<Map<MapKeys.ComplexKey, Integer>>",
- " mapOfComplexKeyAndIntegerProvider;",
- "",
- " private Map getMapOfPackagePrivateEnumAndInteger() {",
- " return ImmutableMap.of(",
- " MapModule_EnumKeyMapKey.create(), MapModule.enumKey());",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.mapOfClassOfAndIntegerProvider =",
- " MapFactory.<Class<?>, Integer>builder(1)",
- " .put(MapModule_ClassKeyMapKey.create(),",
- " MapModule_ClassKeyFactory.create())",
- " .build();",
- " this.mapOfPackagePrivateEnumAndIntegerProvider =",
- " MapFactory.builder(1)",
- " .put(MapModule_EnumKeyMapKey.create(), ",
- " (Provider) MapModule_EnumKeyFactory.create())",
- " .build();",
- " this.mapOfComplexKeyAndIntegerProvider =",
- " MapFactory.<MapKeys.ComplexKey, Integer>builder(3)",
- " .put(",
- " MapModule_ComplexKeyWithInaccessibleValueMapKey.create(),",
- " MapModule_ComplexKeyWithInaccessibleValueFactory.create())",
- " .put(",
- " MapModule_ComplexKeyWithInaccessibleArrayValueMapKey.create(),",
- " MapModule_ComplexKeyWithInaccessibleArrayValueFactory.create())",
- " .put(",
- " MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey.create(),",
- " MapModule_ComplexKeyWithInaccessibleAnnotationValueFactory.create())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Map<Class<?>, Integer> classKey() {",
- " return ImmutableMap.<Class<?>, Integer>of(",
- " MapModule_ClassKeyMapKey.create(), MapModule.classKey());",
- " }",
- "",
- " @Override",
- " public Provider<Map<Class<?>, Integer>> classKeyProvider() {",
- " return mapOfClassOfAndIntegerProvider;",
- " }",
- "",
- " @Override",
- " public Object inaccessibleEnum() {",
- " return getMapOfPackagePrivateEnumAndInteger();",
- " }",
- "",
- " @Override",
- " public Provider<Object> inaccessibleEnumProvider() {",
- " return mapOfPackagePrivateEnumAndIntegerProvider;",
- " }",
- "",
- " @Override",
- " public Map<MapKeys.ComplexKey, Integer> complexKey() {",
- " return ImmutableMap.<MapKeys.ComplexKey, Integer>of(",
- " MapModule_ComplexKeyWithInaccessibleValueMapKey.create(),",
- " MapModule.complexKeyWithInaccessibleValue(),",
- " MapModule_ComplexKeyWithInaccessibleArrayValueMapKey.create(),",
- " MapModule.complexKeyWithInaccessibleArrayValue(),",
- " MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey.create(),",
- " MapModule.complexKeyWithInaccessibleAnnotationValue());",
- " }",
- "",
- " @Override",
- " public Provider<Map<MapKeys.ComplexKey, Integer>> complexKeyProvider() {",
- " return mapOfComplexKeyAndIntegerProvider;",
- " }",
- "}"));
- assertThat(compilation)
- .generatedSourceFile(
- "mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey",
- "package mapkeys;",
- "",
- GENERATED_ANNOTATION,
- "public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {",
- " public static MapKeys.ComplexKey create() {",
- " return MapKeys_ComplexKeyCreator.createComplexKey(",
- " new Class[] {String.class},",
- " String.class,",
- " MapKeys_ComplexKeyCreator.createClassKey(MapKeys.Inaccessible.class));",
- " }",
- "}"));
- assertThat(compilation)
- .generatedSourceFile("mapkeys.MapModule_ClassKeyMapKey")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "mapkeys.MapModule_ClassKeyMapKey",
- "package mapkeys;",
- "",
- GENERATED_ANNOTATION,
- "public final class MapModule_ClassKeyMapKey {",
- " public static Class<?> create() {",
- " return MapKeys.Inaccessible.class;",
- " }",
- "}"));
- }
-
- @Test
- public void mapBindingsWithStringKey() {
- JavaFileObject mapModuleOneFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleOne",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.StringKey;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleOne {",
- " @Provides @IntoMap @StringKey(\"Admin\") Handler provideAdminHandler() {",
- " return new AdminHandler();",
- " }",
- "}");
- JavaFileObject mapModuleTwoFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleTwo",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "final class MapModuleTwo {",
- " @Provides @IntoMap @StringKey(\"Login\") Handler provideLoginHandler() {",
- " return new LoginHandler();",
- " }",
- "}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
- "interface TestComponent {",
- " Provider<Map<String, Provider<Handler>>> dispatcher();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<String, Provider<Handler>>>",
- " mapOfStringAndProviderOfHandlerProvider;",
- "",
- " private Provider<Handler> getProvideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> getProvideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<String, Provider<Handler>>",
- " getMapOfStringAndProviderOfHandler() {",
- " return ImmutableMap.<String, Provider<Handler>>of(",
- " \"Admin\", getProvideAdminHandlerProvider(),",
- " \"Login\", getProvideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfStringAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfStringAndProviderOfHandlerProvider =",
- " (Provider<Map<String, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<String, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .getMapOfStringAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<String, Provider<Handler>>>",
- " mapOfStringAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfStringAndProviderOfHandlerProvider =",
- " MapProviderFactory.<String, Handler>builder(2)",
- " .put(\"Admin\", provideAdminHandlerProvider)",
- " .put(\"Login\", provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
- " return mapOfStringAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- mapModuleOneFile,
- mapModuleTwoFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void mapBindingsWithWrappedKey() {
- JavaFileObject mapModuleOneFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleOne",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleOne {",
- " @Provides @IntoMap",
- " @WrappedClassKey(Integer.class) Handler provideAdminHandler() {",
- " return new AdminHandler();",
- " }",
- "}");
- JavaFileObject mapModuleTwoFile =
- JavaFileObjects
- .forSourceLines("test.MapModuleTwo",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleTwo {",
- " @Provides @IntoMap",
- " @WrappedClassKey(Long.class) Handler provideLoginHandler() {",
- " return new LoginHandler();",
- " }",
- "}");
- JavaFileObject wrappedClassKeyFile = JavaFileObjects.forSourceLines("test.WrappedClassKey",
- "package test;",
- "import dagger.MapKey;",
- "import java.lang.annotation.Retention;",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "@MapKey(unwrapValue = false)",
- "@Retention(RUNTIME)",
- "public @interface WrappedClassKey {",
- " Class<?> value();",
- "}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
- "interface TestComponent {",
- " Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModuleOne mapModuleOne;",
- " private final MapModuleTwo mapModuleTwo;",
- " private volatile Provider<Handler> provideAdminHandlerProvider;",
- " private volatile Provider<Handler> provideLoginHandlerProvider;",
- " private volatile Provider<Map<WrappedClassKey, Provider<Handler>>>",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- "",
- " private DaggerTestComponent(",
- " MapModuleOne mapModuleOneParam,",
- " MapModuleTwo mapModuleTwoParam) {",
- " this.mapModuleOne = mapModuleOneParam;",
- " this.mapModuleTwo = mapModuleTwoParam;",
- " }",
- "",
- " private Provider<Handler> getProvideAdminHandlerProvider() {",
- " Object local = provideAdminHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideAdminHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Provider<Handler> getProvideLoginHandlerProvider() {",
- " Object local = provideLoginHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLoginHandlerProvider = (Provider<Handler>) local;",
- " }",
- " return (Provider<Handler>) local;",
- " }",
- "",
- " private Map<WrappedClassKey, Provider<Handler>>",
- " getMapOfWrappedClassKeyAndProviderOfHandler() {",
- " return ImmutableMap.<WrappedClassKey, Provider<Handler>>of(",
- " WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
- " getProvideAdminHandlerProvider(),",
- " WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
- " getProvideLoginHandlerProvider());",
- " }",
- "",
- " @Override",
- " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
- " Object local = mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
- " (Provider<Map<WrappedClassKey, Provider<Handler>>>) local;",
- " }",
- " return (Provider<Map<WrappedClassKey, Provider<Handler>>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this",
- " .getMapOfWrappedClassKeyAndProviderOfHandler();",
- " case 1:",
- " return (T) MapModuleOne_ProvideAdminHandlerFactory",
- " .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
- " case 2:",
- " return (T) MapModuleTwo_ProvideLoginHandlerFactory",
- " .provideLoginHandler(DaggerTestComponent.this.mapModuleTwo);",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<WrappedClassKey, Provider<Handler>>>",
- " mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfWrappedClassKeyAndProviderOfHandlerProvider =",
- " MapProviderFactory.<WrappedClassKey, Handler>builder(2)",
- " .put(WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
- " provideAdminHandlerProvider)",
- " .put(WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
- " provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
- " return mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- mapModuleOneFile,
- mapModuleTwoFile,
- wrappedClassKeyFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void mapBindingsWithNonProviderValue() {
- JavaFileObject mapModuleOneFile = JavaFileObjects.forSourceLines("test.MapModuleOne",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleOne {",
- " @Provides @IntoMap @PathKey(PathEnum.ADMIN) Handler provideAdminHandler() {",
- " return new AdminHandler();",
- " }",
- "}");
- JavaFileObject mapModuleTwoFile = JavaFileObjects.forSourceLines("test.MapModuleTwo",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModuleTwo {",
- " @Provides @IntoMap @PathKey(PathEnum.LOGIN) Handler provideLoginHandler() {",
- " return new LoginHandler();",
- " }",
- "}");
- JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
- "package test;",
- "import dagger.MapKey;",
- "import java.lang.annotation.Retention;",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "@MapKey(unwrapValue = true)",
- "@Retention(RUNTIME)",
- "public @interface PathKey {",
- " PathEnum value();",
- "}");
- JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
- "package test;",
- "",
- "public enum PathEnum {",
- " ADMIN,",
- " LOGIN;",
- "}");
- JavaFileObject HandlerFile = JavaFileObjects.forSourceLines("test.Handler",
- "package test;",
- "",
- "interface Handler {}");
- JavaFileObject LoginHandlerFile = JavaFileObjects.forSourceLines("test.LoginHandler",
- "package test;",
- "",
- "class LoginHandler implements Handler {",
- " public LoginHandler() {}",
- "}");
- JavaFileObject AdminHandlerFile = JavaFileObjects.forSourceLines("test.AdminHandler",
- "package test;",
- "",
- "class AdminHandler implements Handler {",
- " public AdminHandler() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
- "interface TestComponent {",
- " Provider<Map<PathEnum, Handler>> dispatcher();",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- 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> getMapOfPathEnumAndHandler() {",
- " return ImmutableMap.<PathEnum, Handler>of(",
- " PathEnum.ADMIN,",
- " MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(",
- " mapModuleOne),",
- " PathEnum.LOGIN,",
- " MapModuleTwo_ProvideLoginHandlerFactory.provideLoginHandler(",
- " mapModuleTwo));",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Handler>> dispatcher() {",
- " Object local = mapOfPathEnumAndHandlerProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " mapOfPathEnumAndHandlerProvider = (Provider<Map<PathEnum, Handler>>) local;",
- " }",
- " return (Provider<Map<PathEnum, Handler>>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.getMapOfPathEnumAndHandler();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<Handler> provideAdminHandlerProvider;",
- " private Provider<Handler> provideLoginHandlerProvider;",
- " private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final MapModuleOne mapModuleOneParam,",
- " final MapModuleTwo mapModuleTwoParam) {",
- " this.provideAdminHandlerProvider =",
- " MapModuleOne_ProvideAdminHandlerFactory.create(mapModuleOneParam);",
- " this.provideLoginHandlerProvider =",
- " MapModuleTwo_ProvideLoginHandlerFactory.create(mapModuleTwoParam);",
- " this.mapOfPathEnumAndHandlerProvider =",
- " MapFactory.<PathEnum, Handler>builder(2)",
- " .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
- " .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
- " .build();",
- " }",
- "",
- " @Override",
- " public Provider<Map<PathEnum, Handler>> dispatcher() {",
- " return mapOfPathEnumAndHandlerProvider;",
- " }",
- "}");
- }
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- mapModuleOneFile,
- mapModuleTwoFile,
- enumKeyFile,
- pathEnumFile,
- HandlerFile,
- LoginHandlerFile,
- AdminHandlerFile,
- componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void injectMapWithoutMapBinding() {
- JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.HashMap;",
- "import java.util.Map;",
- "",
- "@Module",
- "final class MapModule {",
- " @Provides Map<String, String> provideAMap() {",
- " Map<String, String> map = new HashMap<String, String>();",
- " map.put(\"Hello\", \"World\");",
- " return map;",
- " }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "",
- "@Component(modules = {MapModule.class})",
- "interface TestComponent {",
- " Map<String, String> dispatcher();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final MapModule mapModule;",
- "",
- " @Override",
- " public Map<String, String> dispatcher() {",
- " return MapModule_ProvideAMapFactory.provideAMap(mapModule);",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(mapModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java b/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
deleted file mode 100644
index 11f6bc1..0000000
--- a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
+++ /dev/null
@@ -1,366 +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;
-
-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.CLASS_PATH_WITHOUT_GUAVA_OPTION;
-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;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 MapBindingExpressionTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public MapBindingExpressionTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void mapBindings() {
- JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- " @Provides @IntoMap @IntKey(0) static int provideInt() { return 0; }",
- " @Provides @IntoMap @LongKey(0) static long provideLong0() { return 0; }",
- " @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
- " @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = MapModule.class)",
- "interface TestComponent {",
- " Map<String, String> strings();",
- " Map<String, Provider<String>> providerStrings();",
- "",
- " Map<Integer, Integer> ints();",
- " Map<Integer, Provider<Integer>> providerInts();",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "}");
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.internal.MapBuilder;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<Integer> provideIntProvider;",
- " private volatile Provider<Long> provideLong0Provider;",
- " private volatile Provider<Long> provideLong1Provider;",
- " private volatile Provider<Long> provideLong2Provider;",
- "",
- " private Provider<Integer> getProvideIntProvider() {",
- " Object local = provideIntProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideIntProvider = (Provider<Integer>) local;",
- " }",
- " return (Provider<Integer>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong0Provider() {",
- " Object local = provideLong0Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong0Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong1Provider() {",
- " Object local = provideLong1Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong1Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong2Provider() {",
- " Object local = provideLong2Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(3);",
- " provideLong2Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }")
- .addLines(
- " @Override",
- " public Map<String, String> strings() {",
- " return Collections.<String, String>emptyMap();",
- " }",
- "",
- " @Override",
- " public Map<String, Provider<String>> providerStrings() {",
- " return Collections.<String, Provider<String>>emptyMap();",
- " }",
- "",
- " @Override",
- " public Map<Integer, Integer> ints() {",
- " return Collections.<Integer, Integer>singletonMap(0, MapModule.provideInt());",
- " }",
- "",
- " @Override",
- " public Map<Integer, Provider<Integer>> providerInts() {",
- " return Collections.<Integer, Provider<Integer>>singletonMap(")
- .addLinesIn(
- DEFAULT_MODE, //
- " 0, MapModule_ProvideIntFactory.create());")
- .addLinesIn(
- FAST_INIT_MODE,
- " 0, getProvideIntProvider());")
- .addLines(
- " }",
- "",
- " @Override",
- " public Map<Long, Long> longs() {",
- " return MapBuilder.<Long, Long>newMapBuilder(3)",
- " .put(0L, MapModule.provideLong0())",
- " .put(1L, MapModule.provideLong1())",
- " .put(2L, MapModule.provideLong2())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return MapBuilder.<Long, Provider<Long>>newMapBuilder(3)")
- .addLinesIn(
- DEFAULT_MODE,
- " .put(0L, MapModule_ProvideLong0Factory.create())",
- " .put(1L, MapModule_ProvideLong1Factory.create())",
- " .put(2L, MapModule_ProvideLong2Factory.create())")
- .addLinesIn(
- FAST_INIT_MODE,
- " .put(0L, getProvideLong0Provider())",
- " .put(1L, getProvideLong1Provider())",
- " .put(2L, getProvideLong2Provider())")
- .addLines( //
- " .build();", " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) (Integer) MapModule.provideInt();",
- " case 1: return (T) (Long) MapModule.provideLong0();",
- " case 2: return (T) (Long) MapModule.provideLong1();",
- " case 3: return (T) (Long) MapModule.provideLong2();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}")
- .build();
- Compilation compilation = daggerCompilerWithoutGuava().compile(mapModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "class Inaccessible {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Map;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Map<Integer, Inaccessible> map) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Map<Integer, Inaccessible> ints();",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newInstance(",
- " (Map) Collections.emptyMap());",
- " }",
- "}");
- Compilation compilation =
- daggerCompilerWithoutGuava().compile(module, inaccessible, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
- " return \"parent value\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "import java.util.Map;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Map<String, Object> objectMap();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private final ParentModule parentModule;",
- "",
- " private final class ChildImpl implements Child {",
- " @Override",
- " public Map<String, Object> objectMap() {",
- " return Collections.<String, Object>singletonMap(",
- " \"parent key\",",
- " ParentModule_ParentKeyObjectFactory.parentKeyObject(",
- " DaggerParent.this.parentModule));",
- " }",
- " }",
- "}");
-
- Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(generatedComponent);
- }
-
- private Compiler daggerCompilerWithoutGuava() {
- 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
deleted file mode 100644
index aa1a715..0000000
--- a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
+++ /dev/null
@@ -1,548 +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;
-
-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_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 MapBindingExpressionWithGuavaTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public MapBindingExpressionWithGuavaTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void mapBindings() {
- JavaFileObject mapModuleFile =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- " @Provides @IntoMap @IntKey(0) static int provideInt() { return 0; }",
- " @Provides @IntoMap @LongKey(0) static long provideLong0() { return 0; }",
- " @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
- " @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
- "}");
- JavaFileObject subcomponentModuleFile =
- JavaFileObjects.forSourceLines(
- "test.SubcomponentMapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface SubcomponentMapModule {",
- " @Provides @IntoMap @LongKey(3) static long provideLong3() { return 3; }",
- " @Provides @IntoMap @LongKey(4) static long provideLong4() { return 4; }",
- " @Provides @IntoMap @LongKey(5) static long provideLong5() { return 5; }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = MapModule.class)",
- "interface TestComponent {",
- " Map<String, String> strings();",
- " Map<String, Provider<String>> providerStrings();",
- "",
- " Map<Integer, Integer> ints();",
- " Map<Integer, Provider<Integer>> providerInts();",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "",
- " Sub sub();",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent(modules = SubcomponentMapModule.class)",
- "interface Sub {",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "}");
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<Integer> provideIntProvider;",
- " private volatile Provider<Long> provideLong0Provider;",
- " private volatile Provider<Long> provideLong1Provider;",
- " private volatile Provider<Long> provideLong2Provider;",
- "",
- " private Provider<Integer> getProvideIntProvider() {",
- " Object local = provideIntProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideIntProvider = (Provider<Integer>) local;",
- " }",
- " return (Provider<Integer>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong0Provider() {",
- " Object local = provideLong0Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong0Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong1Provider() {",
- " Object local = provideLong1Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong1Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong2Provider() {",
- " Object local = provideLong2Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(3);",
- " provideLong2Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }")
- .addLines(
- " @Override",
- " public Map<String, String> strings() {",
- " return ImmutableMap.<String, String>of();",
- " }",
- "",
- " @Override",
- " public Map<String, Provider<String>> providerStrings() {",
- " return ImmutableMap.<String, Provider<String>>of();",
- " }",
- "",
- " @Override",
- " public Map<Integer, Integer> ints() {",
- " return ImmutableMap.<Integer, Integer>of(0, MapModule.provideInt());",
- " }",
- "",
- " @Override",
- " public Map<Integer, Provider<Integer>> providerInts() {",
- " return ImmutableMap.<Integer, Provider<Integer>>of(")
- .addLinesIn(
- DEFAULT_MODE, //
- " 0, MapModule_ProvideIntFactory.create());")
- .addLinesIn(
- FAST_INIT_MODE, //
- " 0, getProvideIntProvider());")
- .addLines(
- " }",
- "",
- " @Override",
- " public Map<Long, Long> longs() {",
- " return ImmutableMap.<Long, Long>of(",
- " 0L, MapModule.provideLong0(),",
- " 1L, MapModule.provideLong1(),",
- " 2L, MapModule.provideLong2());",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>of(")
- .addLinesIn(
- DEFAULT_MODE,
- " 0L, MapModule_ProvideLong0Factory.create(),",
- " 1L, MapModule_ProvideLong1Factory.create(),",
- " 2L, MapModule_ProvideLong2Factory.create());")
- .addLinesIn(
- FAST_INIT_MODE,
- " 0L, getProvideLong0Provider(),",
- " 1L, getProvideLong1Provider(),",
- " 2L, getProvideLong2Provider());")
- .addLines(
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " private final class SubImpl implements Sub {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<Long> provideLong3Provider;",
- " private volatile Provider<Long> provideLong4Provider;",
- " private volatile Provider<Long> provideLong5Provider;",
- " private SubImpl() {}",
- "",
- " private Provider<Long> getProvideLong3Provider() {",
- " Object local = provideLong3Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideLong3Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong4Provider() {",
- " Object local = provideLong4Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " provideLong4Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }",
- "",
- " private Provider<Long> getProvideLong5Provider() {",
- " Object local = provideLong5Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " provideLong5Provider = (Provider<Long>) local;",
- " }",
- " return (Provider<Long>) local;",
- " }")
- .addLines(
- " @Override",
- " public Map<Long, Long> longs() {",
- " return ImmutableMap.<Long, Long>builderWithExpectedSize(6)",
- " .put(0L, MapModule.provideLong0())",
- " .put(1L, MapModule.provideLong1())",
- " .put(2L, MapModule.provideLong2())",
- " .put(3L, SubcomponentMapModule.provideLong3())",
- " .put(4L, SubcomponentMapModule.provideLong4())",
- " .put(5L, SubcomponentMapModule.provideLong5())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>builderWithExpectedSize(6)")
- .addLinesIn(
- DEFAULT_MODE,
- " .put(0L, MapModule_ProvideLong0Factory.create())",
- " .put(1L, MapModule_ProvideLong1Factory.create())",
- " .put(2L, MapModule_ProvideLong2Factory.create())",
- " .put(3L, SubcomponentMapModule_ProvideLong3Factory.create())",
- " .put(4L, SubcomponentMapModule_ProvideLong4Factory.create())",
- " .put(5L, SubcomponentMapModule_ProvideLong5Factory.create())")
- .addLinesIn(
- FAST_INIT_MODE,
- " .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(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) (Long) SubcomponentMapModule.provideLong3();",
- " case 1: return (T) (Long) SubcomponentMapModule.provideLong4();",
- " case 2: return (T) (Long) SubcomponentMapModule.provideLong5();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) (Integer) MapModule.provideInt();",
- " case 1: return (T) (Long) MapModule.provideLong0();",
- " case 2: return (T) (Long) MapModule.provideLong1();",
- " case 3: return (T) (Long) MapModule.provideLong2();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}")
- .build();
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(mapModuleFile, componentFile, subcomponentModuleFile, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible", "package other;", "", "class Inaccessible {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Map;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Map<Integer, Inaccessible> map) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Map<Integer, Inaccessible> ints();",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newInstance((Map) ImmutableMap.of());",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, inaccessible, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
- " return \"parent value\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Map<String, Object> objectMap();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private final ParentModule parentModule;",
- "",
- " private final class ChildImpl implements Child {",
- " @Override",
- " public Map<String, Object> objectMap() {",
- " return ImmutableMap.<String, Object>of(",
- " \"parent key\",",
- " ParentModule_ParentKeyObjectFactory.parentKeyObject(",
- " DaggerParent.this.parentModule));",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void productionComponents() {
- JavaFileObject mapModuleFile =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.Map;",
- "",
- "@ProductionComponent(modules = MapModule.class)",
- "interface TestComponent {",
- " ListenableFuture<Map<String, String>> stringMap();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.producers.internal.CancellationListener;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent, "
- + "CancellationListener {",
- " @Override",
- " public ListenableFuture<Map<String, String>> stringMap() {",
- " return Futures.immediateFuture(",
- " (Map<String, String>) ImmutableMap.<String, String>of());",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {}",
- "}");
- Compilation compilation =
- compilerWithOptions(
- compilerMode
- , CompilerMode.JAVA7
- )
- .compile(mapModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
deleted file mode 100644
index 746c60d..0000000
--- a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
+++ /dev/null
@@ -1,144 +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;
-
-import static com.google.common.truth.Truth.assertAbout;
-import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-
-import com.google.auto.value.processor.AutoAnnotationProcessor;
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 MapKeyProcessorTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public MapKeyProcessorTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void mapKeyCreatorFile() {
- JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.PathKey",
- "package test;",
- "import dagger.MapKey;",
- "import java.lang.annotation.Retention;",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "@MapKey(unwrapValue = false)",
- "@Retention(RUNTIME)",
- "public @interface PathKey {",
- " PathEnum value();",
- " String relativePath() default \"Defaultpath\";",
- "}");
- JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
- "package test;",
- "",
- "public enum PathEnum {",
- " ADMIN,",
- " LOGIN;",
- "}");
- JavaFileObject generatedKeyCreator =
- JavaFileObjects.forSourceLines(
- "test.PathKeyCreator",
- "package test;",
- "",
- "import com.google.auto.value.AutoAnnotation;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class PathKeyCreator {",
- " private PathKeyCreator() {}",
- "",
- " @AutoAnnotation",
- " public static PathKey createPathKey(PathEnum value, String relativePath) {",
- " return new AutoAnnotation_PathKeyCreator_createPathKey(value, relativePath);",
- " }",
- "}");
- assertAbout(javaSources())
- .that(ImmutableList.of(enumKeyFile, pathEnumFile))
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(generatedKeyCreator);
- }
-
- @Test
- public void nestedMapKeyCreatorFile() {
- JavaFileObject enumKeyFile = JavaFileObjects.forSourceLines("test.Container",
- "package test;",
- "import dagger.MapKey;",
- "import java.lang.annotation.Retention;",
- "import static java.lang.annotation.RetentionPolicy.RUNTIME;",
- "",
- "public interface Container {",
- "@MapKey(unwrapValue = false)",
- "@Retention(RUNTIME)",
- "public @interface PathKey {",
- " PathEnum value();",
- " String relativePath() default \"Defaultpath\";",
- "}",
- "}");
- JavaFileObject pathEnumFile = JavaFileObjects.forSourceLines("test.PathEnum",
- "package test;",
- "",
- "public enum PathEnum {",
- " ADMIN,",
- " LOGIN;",
- "}");
- JavaFileObject generatedKeyCreator =
- JavaFileObjects.forSourceLines(
- "test.Container_PathKeyCreator",
- "package test;",
- "",
- "import com.google.auto.value.AutoAnnotation;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class Container_PathKeyCreator {",
- " private Container_PathKeyCreator() {}",
- "",
- " @AutoAnnotation",
- " public static Container.PathKey createPathKey("
- + "PathEnum value, String relativePath) {",
- " return new AutoAnnotation_Container_PathKeyCreator_createPathKey(",
- " value, relativePath);",
- " }",
- "}");
- assertAbout(javaSources())
- .that(ImmutableList.of(enumKeyFile, pathEnumFile))
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor(), new AutoAnnotationProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(generatedKeyCreator);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java b/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
deleted file mode 100644
index 04b0986..0000000
--- a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
+++ /dev/null
@@ -1,332 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-
-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 class MapMultibindingValidationTest {
- @Test
- public void duplicateMapKeys() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.StringKey;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModule {",
- " @Provides @IntoMap @StringKey(\"AKey\") Object provideObjectForAKey() {",
- " return \"one\";",
- " }",
- "",
- " @Provides @IntoMap @StringKey(\"AKey\") Object provideObjectForAKeyAgain() {",
- " return \"one again\";",
- " }",
- "}");
-
- // If they're all there, report only Map<K, V>.
- Compilation compilation =
- daggerCompiler()
- .compile(
- module,
- component(
- "Map<String, Object> objects();",
- "Map<String, Provider<Object>> objectProviders();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "java.util.Map<java.lang.String,java.lang.Object>");
- assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
- assertThat(compilation).hadErrorContaining("provideObjectForAKeyAgain()");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler().withOptions("-Adagger.fullBindingGraphValidation=ERROR").compile(module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>")
- .inFile(module)
- .onLineContaining("class MapModule");
- assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
- assertThat(compilation).hadErrorContaining("provideObjectForAKeyAgain()");
- assertThat(compilation).hadErrorCount(1);
-
- // If there's Map<K, V> and Map<K, Provider<V>>, report only Map<K, V>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- component(
- "Map<String, Object> objects();",
- "Map<String, Provider<Object>> objectProviders();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "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>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- component(
- "Map<String, Object> objects();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "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>>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- component(
- "Map<String, Provider<Object>> objectProviders();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "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();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "java.util.Map<java.lang.String,java.lang.Object>");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler()
- .compile(module, component("Map<String, Provider<Object>> objectProviders();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler()
- .compile(
- module, component("Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "The same map key is bound more than once for "
- + "java.util.Map<java.lang.String,dagger.producers.Producer<java.lang.Object>>");
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void inconsistentMapKeyAnnotations() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.StringKey;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "final class MapModule {",
- " @Provides @IntoMap @StringKey(\"AKey\") Object provideObjectForAKey() {",
- " return \"one\";",
- " }",
- "",
- " @Provides @IntoMap @StringKeyTwo(\"BKey\") Object provideObjectForBKey() {",
- " return \"two\";",
- " }",
- "}");
- JavaFileObject stringKeyTwoFile =
- JavaFileObjects.forSourceLines(
- "test.StringKeyTwo",
- "package test;",
- "",
- "import dagger.MapKey;",
- "",
- "@MapKey(unwrapValue = true)",
- "public @interface StringKeyTwo {",
- " String value();",
- "}");
-
- // If they're all there, report only Map<K, V>.
- Compilation compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component(
- "Map<String, Object> objects();",
- "Map<String, Provider<Object>> objectProviders();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "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 =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(module, stringKeyTwoFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
- + " uses more than one @MapKey annotation type")
- .inFile(module)
- .onLineContaining("class MapModule");
- assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
- assertThat(compilation).hadErrorContaining("provideObjectForBKey()");
- assertThat(compilation).hadErrorCount(1);
-
- // If there's Map<K, V> and Map<K, Provider<V>>, report only Map<K, V>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component(
- "Map<String, Object> objects();",
- "Map<String, Provider<Object>> objectProviders();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,java.lang.Object>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
-
- // If there's Map<K, V> and Map<K, Producer<V>>, report only Map<K, V>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component(
- "Map<String, Object> objects();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,java.lang.Object>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
-
- // If there's Map<K, Provider<V>> and Map<K, Producer<V>>, report only Map<K, Provider<V>>.
- compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component(
- "Map<String, Provider<Object>> objectProviders();",
- "Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler()
- .compile(module, stringKeyTwoFile, component("Map<String, Object> objects();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,java.lang.Object>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component("Map<String, Provider<Object>> objectProviders();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
-
- compilation =
- daggerCompiler()
- .compile(
- module,
- stringKeyTwoFile,
- component("Producer<Map<String, Producer<Object>>> objectProducers();"));
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,dagger.producers.Producer<java.lang.Object>>"
- + " uses more than one @MapKey annotation type");
- assertThat(compilation).hadErrorCount(1);
- }
-
- private static JavaFileObject component(String... entryPoints) {
- return JavaFileObjects.forSourceLines(
- "test.TestComponent",
- ImmutableList.<String>builder()
- .add(
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.producers.Producer;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {MapModule.class})",
- "interface TestComponent {")
- .add(entryPoints)
- .add("}")
- .build());
- }
-}
diff --git a/javatests/dagger/internal/codegen/MembersInjectionTest.java b/javatests/dagger/internal/codegen/MembersInjectionTest.java
deleted file mode 100644
index edaedaf..0000000
--- a/javatests/dagger/internal/codegen/MembersInjectionTest.java
+++ /dev/null
@@ -1,1531 +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;
-
-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 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.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;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.TypeElement;
-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 MembersInjectionTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public MembersInjectionTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void parentClass_noInjectedMembers() {
- JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "public final class Child extends Parent {",
- " @Inject Child() {}",
- "}");
- JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "public abstract class Parent {}");
-
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " Child child();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Child child() {",
- " return new Child();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(childFile, parentFile, componentFile);
-
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void parentClass_injectedMembersInSupertype() {
- JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "public final class Child extends Parent {",
- " @Inject Child() {}",
- "}");
- JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "public abstract class Parent {",
- " @Inject Dep dep;",
- "}");
- JavaFileObject depFile = JavaFileObjects.forSourceLines("test.Dep",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class Dep {",
- " @Inject Dep() {}",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " Child child();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Child child() {",
- " return injectChild(Child_Factory.newInstance());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private Child injectChild(Child instance) {",
- " Parent_MembersInjector.injectDep(instance, new Dep());",
- " return instance;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(childFile, parentFile, depFile, componentFile);
-
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test public void fieldAndMethodGenerics() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GenericClass<A, B> {",
- " @Inject A a;",
- "",
- " @Inject GenericClass() {}",
- "",
- " @Inject void register(B 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expected);
- }
-
- @Test public void subclassedGenericMembersInjectors() {
- JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A() {}",
- "}");
- JavaFileObject a2 = JavaFileObjects.forSourceLines("test.A2",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A2 {",
- " @Inject A2() {}",
- "}");
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Parent<X, Y> {",
- " @Inject X x;",
- " @Inject Y y;",
- " @Inject A2 a2;",
- "",
- " @Inject Parent() {}",
- "}");
- JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Child<T> extends Parent<T, A> {",
- " @Inject A a;",
- " @Inject T t;",
- "",
- " @Inject Child() {}",
- "}");
- 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expected);
- }
-
- @Test public void fieldInjection() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.FieldInjection",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class FieldInjection {",
- " @Inject String string;",
- " @Inject Lazy<String> lazyString;",
- " @Inject Provider<String> stringProvider;",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.FieldInjection_MembersInjector",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import dagger.MembersInjector;",
- "import dagger.internal.DoubleCheck;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class FieldInjection_MembersInjector",
- " implements MembersInjector<FieldInjection> {",
- " private final Provider<String> stringProvider;",
- "",
- " public FieldInjection_MembersInjector(Provider<String> stringProvider) {",
- " this.stringProvider = stringProvider;",
- " }",
- "",
- " public static MembersInjector<FieldInjection> create(",
- " Provider<String> stringProvider) {",
- " return new FieldInjection_MembersInjector(stringProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(FieldInjection instance) {",
- " injectString(instance, stringProvider.get());",
- " injectLazyString(instance, DoubleCheck.lazy(stringProvider));",
- " injectStringProvider(instance, stringProvider);",
- " }",
- "",
- " public static void injectString(Object instance, String string) {",
- " ((FieldInjection) instance).string = string;",
- " }",
- "",
- " public static void injectLazyString(Object instance, Lazy<String> lazyString) {",
- " ((FieldInjection) instance).lazyString = lazyString;",
- " }",
- "",
- " public static void injectStringProvider(",
- " Object instance, Provider<String> stringProvider) {",
- " ((FieldInjection) instance).stringProvider = stringProvider;",
- " }",
- "}");
- 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;",
- "",
- "import dagger.Lazy;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class MethodInjection {",
- " @Inject void noArgs() {}",
- " @Inject void oneArg(String string) {}",
- " @Inject void manyArgs(",
- " String string, Lazy<String> lazyString, Provider<String> stringProvider) {}",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.MethodInjection_MembersInjector",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import dagger.MembersInjector;",
- "import dagger.internal.DoubleCheck;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class MethodInjection_MembersInjector",
- " implements MembersInjector<MethodInjection> {",
- "",
- " private final Provider<String> stringProvider;",
- "",
- " public MethodInjection_MembersInjector(Provider<String> stringProvider) {",
- " this.stringProvider = stringProvider;",
- " }",
- "",
- " public static MembersInjector<MethodInjection> create(",
- " Provider<String> stringProvider) {",
- " return new MethodInjection_MembersInjector(stringProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(MethodInjection instance) {",
- " injectNoArgs(instance);",
- " injectOneArg(instance, stringProvider.get());",
- " injectManyArgs(",
- " instance,",
- " stringProvider.get(),",
- " DoubleCheck.lazy(stringProvider),",
- " stringProvider);",
- " }",
- "",
- " public static void injectNoArgs(Object instance) {",
- " ((MethodInjection) instance).noArgs();",
- " }",
- "",
- " public static void injectOneArg(Object instance, String string) {",
- " ((MethodInjection) instance).oneArg(string);",
- " }",
- "",
- " public static void injectManyArgs(",
- " Object instance,",
- " String string,",
- " Lazy<String> lazyString,",
- " Provider<String> stringProvider) {",
- " ((MethodInjection) instance).manyArgs(string, lazyString, stringProvider);",
- " }",
- "}");
- assertAbout(javaSource())
- .that(file)
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expected);
- }
-
- @Test
- public void mixedMemberInjection() {
- JavaFileObject file = JavaFileObjects.forSourceLines(
- "test.MixedMemberInjection",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class MixedMemberInjection {",
- " @Inject String string;",
- " @Inject void setString(String s) {}",
- " @Inject Object object;",
- " @Inject void setObject(Object 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expected);
- }
-
- @Test public void injectConstructorAndMembersInjection() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class AllInjections {",
- " @Inject String s;",
- " @Inject AllInjections(String s) {}",
- " @Inject void s(String 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expectedMembersInjector);
- }
-
- @Test public void supertypeMembersInjection() {
- JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
- "package test;",
- "",
- "class A {}");
- JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class B extends A {",
- " @Inject String 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expectedMembersInjector);
- }
-
- @Test
- public void simpleComponentWithNesting() {
- JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines(
- "test.OuterType",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "",
- "final class OuterType {",
- " static class A {",
- " @Inject A() {}",
- " }",
- " static class B {",
- " @Inject A a;",
- " }",
- " @Component interface SimpleComponent {",
- " A a();",
- " void inject(B b);",
- " }",
- "}");
- 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())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(bMembersInjector);
- }
-
- @Test
- public void componentWithNestingAndGeneratedType() {
- JavaFileObject nestedTypesFile =
- JavaFileObjects.forSourceLines(
- "test.OuterType",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "",
- "final class OuterType {",
- " @Inject GeneratedType generated;",
- " static class A {",
- " @Inject A() {}",
- " }",
- " static class B {",
- " @Inject A a;",
- " }",
- " @Component interface SimpleComponent {",
- " A a();",
- " void inject(B b);",
- " }",
- "}");
- 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(javaSource())
- .that(nestedTypesFile)
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(
- new ComponentProcessor(),
- new AbstractProcessor() {
- private boolean done;
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of("*");
- }
-
- @Override
- public boolean process(
- Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- if (!done) {
- done = true;
- try (Writer writer =
- processingEnv
- .getFiler()
- .createSourceFile("test.GeneratedType")
- .openWriter()) {
- writer.write(
- Joiner.on('\n')
- .join(
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class GeneratedType {",
- " @Inject GeneratedType() {}",
- "}"));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- return false;
- }
- })
- .compilesWithoutError()
- .and()
- .generatesSources(bMembersInjector);
- }
-
- @Test
- public void lowerCaseNamedMembersInjector_forLowerCaseType() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class foo {",
- " @Inject String string;",
- "}");
- JavaFileObject fooModule =
- JavaFileObjects.forSourceLines(
- "test.fooModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class fooModule {",
- " @Provides String string() { return \"foo\"; }",
- "}");
- JavaFileObject fooComponent =
- JavaFileObjects.forSourceLines(
- "test.fooComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = fooModule.class)",
- "interface fooComponent {",
- " void inject(foo target);",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(foo, fooModule, fooComponent);
- assertThat(compilation).succeeded();
- assertThat(compilation).generatedFile(CLASS_OUTPUT, "test", "foo_MembersInjector.class");
- }
-
- @Test
- public void fieldInjectionForShadowedMember() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Parent { ",
- " @Inject Foo object;",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Child extends Parent { ",
- " @Inject Bar object;",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface C { ",
- " void inject(Child child);",
- "}");
-
- JavaFileObject expectedMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.Child_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class Child_MembersInjector implements MembersInjector<Child> {",
- " private final Provider<Foo> objectProvider;",
- " private final Provider<Bar> objectProvider2;",
- "",
- " public Child_MembersInjector(",
- " Provider<Foo> objectProvider, Provider<Bar> objectProvider2) {",
- " this.objectProvider = objectProvider;",
- " this.objectProvider2 = objectProvider2;",
- " }",
- "",
- " public static MembersInjector<Child> create(",
- " Provider<Foo> objectProvider, Provider<Bar> objectProvider2) {",
- " return new Child_MembersInjector(objectProvider, objectProvider2);",
- " }",
- "",
- " @Override",
- " public void injectMembers(Child instance) {",
- " Parent_MembersInjector.injectObject(instance, objectProvider.get());",
- " injectObject(instance, objectProvider2.get());",
- " }",
- "",
- " public static void injectObject(Object instance, Object object) {",
- " ((Child) instance).object = (Bar) object;",
- " }",
- "}");
-
- assertAbout(javaSources())
- .that(ImmutableList.of(foo, bar, parent, child, component))
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expectedMembersInjector);
- }
-
- @Test public void privateNestedClassError() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class InnerClass {",
- " @Inject int field;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateNestedClassWarning() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static final class InnerClass {",
- " @Inject int field;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- compilerMode.javacopts().append("-Adagger.privateMemberValidation=WARNING"))
- .compile(file);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining("Dagger does not support injection into private classes")
- .inFile(file)
- .onLine(6);
- }
-
- @Test public void privateSuperclassIsOkIfNotInjectedInto() {
- JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class OuterClass {",
- " private static class BaseClass {}",
- "",
- " static final class DerivedClass extends BaseClass {",
- " @Inject int field;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void rawFrameworkTypeField() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.RawFrameworkTypes",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class RawProviderField {",
- " @Inject Provider fieldWithRawProvider;",
- "}",
- "",
- "@Component",
- "interface C {",
- " void inject(RawProviderField rawProviderField);",
- "}");
-
- Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("javax.inject.Provider cannot be provided")
- .inFile(file)
- .onLineContaining("interface C");
- }
-
- @Test
- public void rawFrameworkTypeParameter() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.RawFrameworkTypes",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class RawProviderParameter {",
- " @Inject void methodInjection(Provider rawProviderParameter) {}",
- "}",
- "",
- "@Component",
- "interface C {",
- " void inject(RawProviderParameter rawProviderParameter);",
- "}");
-
- Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("javax.inject.Provider cannot be provided")
- .inFile(file)
- .onLineContaining("interface C");
- }
-
- @Test
- public void injectsPrimitive() {
- JavaFileObject injectedType =
- JavaFileObjects.forSourceLines(
- "test.InjectedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class InjectedType {",
- " @Inject InjectedType() {}",
- "",
- " @Inject int primitiveInt;",
- " @Inject Integer boxedInt;",
- "}");
- JavaFileObject membersInjector =
- JavaFileObjects.forSourceLines(
- "test.InjectedType_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectedType_MembersInjector ",
- " implements MembersInjector<InjectedType> {",
- " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;",
- "",
- " public InjectedType_MembersInjector(",
- " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
- " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;",
- " }",
- "",
- " public static MembersInjector<InjectedType> create(",
- " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
- " return new InjectedType_MembersInjector(boxedIntAndPrimitiveIntProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(InjectedType instance) {",
- " injectPrimitiveInt(instance, boxedIntAndPrimitiveIntProvider.get());",
- " injectBoxedInt(instance, boxedIntAndPrimitiveIntProvider.get());",
- " }",
- "",
- " public static void injectPrimitiveInt(Object instance, int primitiveInt) {",
- " ((InjectedType) instance).primitiveInt = primitiveInt;",
- " }",
- "",
- " public static void injectBoxedInt(Object instance, Integer boxedInt) {",
- " ((InjectedType) instance).boxedInt = boxedInt;",
- " }",
- "}");
- JavaFileObject factory =
- JavaFileObjects.forSourceLines(
- "test.InjectedType_Factory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class InjectedType_Factory implements Factory<InjectedType> {",
- " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;",
- "",
- " public InjectedType_Factory(Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
- " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;",
- " }",
- "",
- " @Override",
- " public InjectedType get() {",
- " InjectedType instance = new InjectedType();",
- " InjectedType_MembersInjector.injectPrimitiveInt(",
- " instance, boxedIntAndPrimitiveIntProvider.get());",
- " InjectedType_MembersInjector.injectBoxedInt(",
- " instance, boxedIntAndPrimitiveIntProvider.get());",
- " return instance;",
- " }",
- "",
- " public static InjectedType_Factory create(",
- " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
- " return new InjectedType_Factory(boxedIntAndPrimitiveIntProvider);",
- " }",
- "",
- " public static InjectedType newInstance() {",
- " return new InjectedType();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(injectedType);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.InjectedType_MembersInjector")
- .hasSourceEquivalentTo(membersInjector);
- assertThat(compilation)
- .generatedSourceFile("test.InjectedType_Factory")
- .hasSourceEquivalentTo(factory);
- }
-
- @Test
- public void accessibility() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "other.Foo",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Inaccessible {",
- " @Inject Inaccessible() {}",
- " @Inject Foo foo;",
- " @Inject void method(Foo foo) {}",
- "}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Inaccessible inaccessible) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import other.UsesInaccessible;",
- "",
- "@Component",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(foo, inaccessible, usesInaccessible, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("other.Inaccessible_MembersInjector")
- .hasSourceEquivalentTo(
- JavaFileObjects.forSourceLines(
- "other.Inaccessible_MembersInjector",
- "package other;",
- "",
- "import dagger.MembersInjector;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class Inaccessible_MembersInjector",
- " implements MembersInjector<Inaccessible> {",
- " private final Provider<Foo> fooProvider;",
- "",
- " public Inaccessible_MembersInjector(Provider<Foo> fooProvider) {",
- " this.fooProvider = fooProvider;",
- " }",
- "",
- " 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, fooProvider.get());",
- " }",
- "",
- " public static void injectFoo(Object instance, Object foo) {",
- " ((Inaccessible) instance).foo = (Foo) foo;",
- " }",
- "",
- " public static void injectMethod(Object instance, Object foo) {",
- " ((Inaccessible) instance).method((Foo) foo);",
- " }",
- "}"));
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- IMPORT_GENERATED_ANNOTATION,
- "import other.Foo_Factory;",
- "import other.Inaccessible_Factory;",
- "import other.Inaccessible_MembersInjector;",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Object getInaccessible() {",
- " return injectInaccessible(Inaccessible_Factory.newInstance());",
- " }",
- "",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newInstance(",
- " getInaccessible());",
- " }",
- "",
- // TODO(ronshapiro): if possible, it would be great to rename "instance", but we
- // need to make sure that this doesn't conflict with any framework field in this or
- // any parent component
- " @CanIgnoreReturnValue",
- " private Object injectInaccessible(Object instance) {",
- " Inaccessible_MembersInjector.injectFoo(instance, Foo_Factory.newInstance());",
- " Inaccessible_MembersInjector.injectMethod(instance, Foo_Factory.newInstance());",
- " return instance;",
- " }",
- "}");
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void accessibleRawType_ofInaccessibleType() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "class Inaccessible {}");
- JavaFileObject inaccessiblesModule =
- JavaFileObjects.forSourceLines(
- "other.InaccessiblesModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.ArrayList;",
- "import java.util.List;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "public class InaccessiblesModule {",
- // force Provider initialization
- " @Provides @Singleton static List<Inaccessible> inaccessibles() {",
- " return new ArrayList<>();",
- " }",
- "}");
- JavaFileObject usesInaccessibles =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessibles",
- "package other;",
- "",
- "import java.util.List;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessibles {",
- " @Inject UsesInaccessibles() {}",
- " @Inject List<Inaccessible> inaccessibles;",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "import other.UsesInaccessibles;",
- "",
- "@Singleton",
- "@Component(modules = other.InaccessiblesModule.class)",
- "interface TestComponent {",
- " UsesInaccessibles usesInaccessibles();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(inaccessible, inaccessiblesModule, usesInaccessibles, component);
- assertThat(compilation).succeeded();
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "import other.InaccessiblesModule;",
- "import other.InaccessiblesModule_InaccessiblesFactory;",
- "import other.UsesInaccessibles;",
- "import other.UsesInaccessibles_Factory;",
- "import other.UsesInaccessibles_MembersInjector;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Object listOfInaccessible = new MemoizedSentinel();",
- "",
- " private List getListOfInaccessible() {",
- " Object local = listOfInaccessible;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = listOfInaccessible;",
- " if (local instanceof MemoizedSentinel) {",
- " local = InaccessiblesModule_InaccessiblesFactory.inaccessibles();",
- " listOfInaccessible =",
- " DoubleCheck.reentrantCheck(listOfInaccessible, local);",
- " }",
- " }",
- " }",
- " return (List) local;",
- " }")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"rawtypes\")",
- " private Provider inaccessiblesProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.inaccessiblesProvider =",
- " DoubleCheck.provider(InaccessiblesModule_InaccessiblesFactory.create());",
- " }")
- .addLines(
- "",
- " @Override",
- " public UsesInaccessibles usesInaccessibles() {",
- " return injectUsesInaccessibles(",
- " UsesInaccessibles_Factory.newInstance());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private UsesInaccessibles injectUsesInaccessibles(",
- " UsesInaccessibles instance) {",
- " UsesInaccessibles_MembersInjector.injectInaccessibles(")
- .addLinesIn(
- FAST_INIT_MODE,
- " instance, (List) getListOfInaccessible());")
- .addLinesIn(
- DEFAULT_MODE,
- " instance, (List) inaccessiblesProvider.get());")
- .addLines(
- " return instance;",
- " }",
- "}")
- .build();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void publicSupertypeHiddenSubtype() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "other.Foo",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "other.Supertype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class Supertype<T> {",
- " @Inject T t;",
- "}");
- JavaFileObject subtype =
- JavaFileObjects.forSourceLines(
- "other.Subtype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Subtype extends Supertype<Foo> {",
- " @Inject Subtype() {}",
- "}");
- JavaFileObject injectsSubtype =
- JavaFileObjects.forSourceLines(
- "other.InjectsSubtype",
- "package other;",
- "",
- "import javax.inject.Inject;",
- "",
- "public class InjectsSubtype {",
- " @Inject InjectsSubtype(Subtype s) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " other.InjectsSubtype injectsSubtype();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(foo, supertype, subtype, injectsSubtype, component);
- assertThat(compilation).succeeded();
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.errorprone.annotations.CanIgnoreReturnValue;",
- "import other.Foo_Factory;",
- "import other.InjectsSubtype;",
- "import other.InjectsSubtype_Factory;",
- "import other.Subtype_Factory;",
- "import other.Supertype;",
- "import other.Supertype_MembersInjector;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Object getSubtype() {",
- " return injectSubtype(Subtype_Factory.newInstance());",
- " }",
- "",
- " @Override",
- " public InjectsSubtype injectsSubtype() {",
- " return InjectsSubtype_Factory.newInstance(getSubtype());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private Object injectSubtype(Object instance) {",
- " Supertype_MembersInjector.injectT(",
- " (Supertype) instance, Foo_Factory.newInstance());",
- " return instance;",
- " }",
- "}");
-
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java b/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
deleted file mode 100644
index 68d5daa..0000000
--- a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
+++ /dev/null
@@ -1,239 +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 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 that errors are reported for invalid members injection methods and {@link
- * dagger.MembersInjector} dependency requests.
- */
-@RunWith(JUnit4.class)
-public class MembersInjectionValidationTest {
- @Test
- public void membersInjectDependsOnUnboundedType() {
- JavaFileObject injectsUnboundedType =
- JavaFileObjects.forSourceLines(
- "test.InjectsUnboundedType",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import java.util.ArrayList;",
- "import javax.inject.Inject;",
- "",
- "class InjectsUnboundedType {",
- " @Inject MembersInjector<ArrayList<?>> listInjector;",
- "}");
-
- Compilation compilation = daggerCompiler().compile(injectsUnboundedType);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot inject members into types with unbounded type arguments: "
- + "java.util.ArrayList<?>")
- .inFile(injectsUnboundedType)
- .onLineContaining("@Inject MembersInjector<ArrayList<?>> listInjector;");
- }
-
- @Test
- public void membersInjectPrimitive() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " void inject(int primitive);",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into int")
- .inFile(component)
- .onLineContaining("void inject(int primitive);");
- }
-
- @Test
- public void membersInjectArray() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " void inject(Object[] array);",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into java.lang.Object[]")
- .inFile(component)
- .onLineContaining("void inject(Object[] array);");
- }
-
- @Test
- public void membersInjectorOfArray() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "",
- "@Component",
- "interface TestComponent {",
- " MembersInjector<Object[]> objectArrayInjector();",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into java.lang.Object[]")
- .inFile(component)
- .onLineContaining("objectArrayInjector();");
- }
-
- @Test
- public void membersInjectRawType() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "",
- "@Component",
- "interface TestComponent {",
- " void inject(Set rawSet);",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("Cannot inject members into raw type java.util.Set");
- }
-
- @Test
- public void qualifiedMembersInjector() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "import javax.inject.Named;",
- "",
- "@Component",
- "interface TestComponent {",
- " @Named(\"foo\") MembersInjector<Object> objectInjector();",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into qualified types")
- .inFile(component)
- .onLineContaining("objectInjector();");
- }
-
- @Test
- public void qualifiedMembersInjectionMethod() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "import javax.inject.Named;",
- "",
- "@Component",
- "interface TestComponent {",
- " @Named(\"foo\") void injectObject(Object object);",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into qualified types")
- .inFile(component)
- .onLineContaining("injectObject(Object object);");
- }
-
- @Test
- public void qualifiedMembersInjectionMethodParameter() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "import javax.inject.Named;",
- "",
- "@Component",
- "interface TestComponent {",
- " void injectObject(@Named(\"foo\") Object object);",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into qualified types")
- .inFile(component)
- .onLineContaining("injectObject(@Named(\"foo\") Object object);");
- }
-
- @Test
- public void staticFieldInjection() {
- JavaFileObject injected =
- JavaFileObjects.forSourceLines(
- "test.Injected",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class Injected {",
- " @Inject static Object object;",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " void inject(Injected injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(injected, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("static fields").inFile(injected).onLine(6);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java b/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
deleted file mode 100644
index 687c29a..0000000
--- a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
+++ /dev/null
@@ -1,74 +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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.testing.compile.CompilationRule;
-import dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.InnerClass;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MethodSignatureFormatterTest {
- @Rule public CompilationRule compilationRule = new CompilationRule();
-
- static class OuterClass {
- @interface Foo {
- Class<?> bar();
- }
-
- static class InnerClass {
- @Foo(bar = String.class)
- @Singleton
- String foo(
- @SuppressWarnings("unused") int a,
- @SuppressWarnings("unused") ImmutableList<Boolean> blah) {
- return "foo";
- }
- }
- }
-
- @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).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.
- assertThat(formatted).contains("@Singleton");
- assertThat(formatted).doesNotContain("@javax.inject.Singleton"); // maybe more importantly
- assertThat(formatted)
- .contains("@dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.Foo"
- + "(bar=String.class)");
- assertThat(formatted).contains(" String "); // return type compressed
- assertThat(formatted).contains("int, ImmutableList<Boolean>)"); // parameters compressed.
- }
-}
diff --git a/javatests/dagger/internal/codegen/MissingAndroidProcessorTest.java b/javatests/dagger/internal/codegen/MissingAndroidProcessorTest.java
deleted file mode 100644
index 0f91e0e..0000000
--- a/javatests/dagger/internal/codegen/MissingAndroidProcessorTest.java
+++ /dev/null
@@ -1,59 +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;
-
-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 class MissingAndroidProcessorTest {
- @Test
- public void missingProcessor() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.android.ContributesAndroidInjector;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface TestModule {",
- " @ContributesAndroidInjector",
- " Object o();",
- "}");
- JavaFileObject contributesAndroidInjectorStub =
- JavaFileObjects.forSourceLines(
- "dagger.android.ContributesAndroidInjector",
- "package dagger.android;",
- "",
- "public @interface ContributesAndroidInjector {}");
- Compilation compilation = daggerCompiler().compile(module, contributesAndroidInjectorStub);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("dagger.android.processor.AndroidProcessor")
- .inFile(module)
- .onLine(9);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java b/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
deleted file mode 100644
index e2f9634..0000000
--- a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
+++ /dev/null
@@ -1,160 +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;
-
-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 class MissingBindingSuggestionsTest {
- private static JavaFileObject injectable(String className, String constructorParams) {
- return JavaFileObjects.forSourceLines("test." + className,
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class " + className +" {",
- " @Inject " + className + "(" + constructorParams + ") {}",
- "}");
- }
-
- private static JavaFileObject emptyInterface(String interfaceName) {
- return JavaFileObjects.forSourceLines("test." + interfaceName,
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "interface " + interfaceName +" {}");
- }
-
- @Test public void suggestsBindingInSeparateComponent() {
- JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface FooComponent {",
- " Foo getFoo();",
- "}");
- JavaFileObject barModule = JavaFileObjects.forSourceLines("test.BarModule",
- "package test;",
- "",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "@dagger.Module",
- "final class BarModule {",
- " @Provides Bar provideBar() {return null;}",
- "}");
- JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = {BarModule.class})",
- "interface BarComponent {",
- " Bar getBar();",
- "}");
- JavaFileObject foo = injectable("Foo", "Bar bar");
- JavaFileObject bar = emptyInterface("Bar");
-
- JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TopComponent {",
- " FooComponent getFoo();",
- " BarComponent getBar(BarModule barModule);",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(fooComponent, barComponent, topComponent, foo, bar, barModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("A binding with matching key exists in component: test.BarComponent");
- }
-
- @Test public void suggestsBindingInNestedSubcomponent() {
- JavaFileObject fooComponent = JavaFileObjects.forSourceLines("test.FooComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface FooComponent {",
- " Foo getFoo();",
- "}");
- JavaFileObject barComponent = JavaFileObjects.forSourceLines("test.BarComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent()",
- "interface BarComponent {",
- " BazComponent getBaz();",
- "}");
- JavaFileObject bazModule = JavaFileObjects.forSourceLines("test.BazModule",
- "package test;",
- "",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "@dagger.Module",
- "final class BazModule {",
- " @Provides Baz provideBaz() {return null;}",
- "}");
- JavaFileObject bazComponent = JavaFileObjects.forSourceLines("test.BazComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = {BazModule.class})",
- "interface BazComponent {",
- " Baz getBaz();",
- "}");
- JavaFileObject foo = injectable("Foo", "Baz baz");
- JavaFileObject baz = emptyInterface("Baz");
-
- JavaFileObject topComponent = JavaFileObjects.forSourceLines("test.TopComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TopComponent {",
- " FooComponent getFoo();",
- " BarComponent getBar();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .compile(fooComponent, barComponent, bazComponent, topComponent, foo, baz, bazModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .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
deleted file mode 100644
index 8eaa8d5..0000000
--- a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
+++ /dev/null
@@ -1,780 +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 dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.message;
-
-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 MissingBindingValidationTest {
- @Test
- public void dependOnInterface() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface MyComponent {",
- " Foo getFoo();",
- "}");
- JavaFileObject injectable = JavaFileObjects.forSourceLines("test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Bar bar) {}",
- "}");
- JavaFileObject nonInjectable = JavaFileObjects.forSourceLines("test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "interface Bar {}");
- Compilation compilation = daggerCompiler().compile(component, injectable, nonInjectable);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.Bar cannot be provided without an @Provides-annotated method.")
- .inFile(component)
- .onLineContaining("interface MyComponent");
- }
-
- @Test
- public void entryPointDependsOnInterface() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " @Component()",
- " interface AComponent {",
- " A getA();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "[Dagger/MissingBinding] test.TestClass.A cannot be provided "
- + "without an @Provides-annotated method.")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test
- public void entryPointDependsOnQualifiedInterface() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Qualifier;",
- "",
- "final class TestClass {",
- " @Qualifier @interface Q {}",
- " interface A {}",
- "",
- " @Component()",
- " interface AComponent {",
- " @Q A qualifiedA();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "[Dagger/MissingBinding] @test.TestClass.Q test.TestClass.A cannot be provided "
- + "without an @Provides-annotated method.")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test public void constructorInjectionWithoutAnnotation() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class TestClass {",
- " static class A {",
- " A() {}",
- " }",
- "",
- " @Component()",
- " interface AComponent {",
- " A getA();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.TestClass.A cannot be provided without an @Inject constructor or an "
- + "@Provides-annotated method.")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test public void membersInjectWithoutProvision() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "final class TestClass {",
- " static class A {",
- " @Inject A() {}",
- " }",
- "",
- " static class B {",
- " @Inject A a;",
- " }",
- "",
- " @Component()",
- " interface AComponent {",
- " B getB();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "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)
- .onLineContaining("interface AComponent");
- }
-
- @Test
- public void missingBindingWithSameKeyAsMembersInjectionMethod() {
- JavaFileObject self =
- JavaFileObjects.forSourceLines(
- "test.Self",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class Self {",
- " @Inject Provider<Self> selfProvider;",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.SelfComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SelfComponent {",
- " void inject(Self target);",
- "}");
-
- Compilation compilation = daggerCompiler().compile(self, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.Self cannot be provided without an @Inject constructor")
- .inFile(component)
- .onLineContaining("interface SelfComponent");
- }
-
- @Test
- public void genericInjectClassWithWildcardDependencies() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " Foo<? extends Number> foo();",
- "}");
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class Foo<T> {",
- " @Inject Foo(T t) {}",
- "}");
- Compilation compilation = daggerCompiler().compile(component, foo);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Foo<? extends java.lang.Number> cannot be provided "
- + "without an @Provides-annotated method");
- }
-
- @Test public void longChainOfDependencies() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "import javax.inject.Named;",
- "import javax.inject.Provider;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " static class B {",
- " @Inject B(A a) {}",
- " }",
- "",
- " static class C {",
- " @Inject B b;",
- " @Inject C(X x) {}",
- " }",
- "",
- " interface D { }",
- "",
- " static class DImpl implements D {",
- " @Inject DImpl(C c, B b) {}",
- " }",
- "",
- " static class X {",
- " @Inject X() {}",
- " }",
- "",
- " @Module",
- " static class DModule {",
- " @Provides @Named(\"slim shady\") D d(X x1, DImpl impl, X x2) { return impl; }",
- " }",
- "",
- " @Component(modules = { DModule.class })",
- " interface AComponent {",
- " @Named(\"slim shady\") D getFoo();",
- " C injectC(C c);",
- " Provider<C> cProvider();",
- " Lazy<C> lazyC();",
- " Provider<Lazy<C>> lazyCProvider();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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:",
- " test.TestClass.AComponent.getFoo()",
- " test.TestClass.AComponent.cProvider()",
- " test.TestClass.AComponent.lazyC()",
- " test.TestClass.AComponent.lazyCProvider()"))
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test
- public void bindsMethodAppearsInTrace() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "TestComponent",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " TestInterface testInterface();",
- "}");
- JavaFileObject interfaceFile =
- JavaFileObjects.forSourceLines("TestInterface", "interface TestInterface {}");
- JavaFileObject implementationFile =
- JavaFileObjects.forSourceLines(
- "TestImplementation",
- "import javax.inject.Inject;",
- "",
- "final class TestImplementation implements TestInterface {",
- " @Inject TestImplementation(String missingBinding) {}",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "TestModule",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface TestModule {",
- " @Binds abstract TestInterface bindTestInterface(TestImplementation implementation);",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(component, module, interfaceFile, implementationFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.lang.String cannot be provided without an @Inject constructor or an "
- + "@Provides-annotated method.",
- " java.lang.String is injected at",
- " TestImplementation(missingBinding)",
- " TestImplementation is injected at",
- " TestModule.bindTestInterface(implementation)",
- " TestInterface is provided at",
- " TestComponent.testInterface()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test public void resolvedParametersInDependencyTrace() {
- JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class Generic<T> {",
- " @Inject Generic(T t) {}",
- "}");
- JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import java.util.List;",
- "",
- "final class TestClass {",
- " @Inject TestClass(List list) {}",
- "}");
- JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class UsesTest {",
- " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
- "}");
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " UsesTest usesTest();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(generic, testClass, usesTest, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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() {
- JavaFileObject generic = JavaFileObjects.forSourceLines("test.Generic",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class Generic<T> {",
- " @Inject T t;",
- " @Inject Generic() {}",
- "}");
- JavaFileObject testClass = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import java.util.List;",
- "",
- "final class TestClass {",
- " @Inject TestClass(List list) {}",
- "}");
- JavaFileObject usesTest = JavaFileObjects.forSourceLines("test.UsesTest",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class UsesTest {",
- " @Inject UsesTest(Generic<TestClass> genericTestClass) {}",
- "}");
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " UsesTest usesTest();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(generic, testClass, usesTest, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "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 bindingUsedOnlyInSubcomponentDependsOnBindingOnlyInSubcomponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "Parent",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "ParentModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides static Object needsString(String string) {",
- " return \"needs string: \" + string;",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "Child",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface Child {",
- " String string();",
- " Object needsString();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "ChildModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildModule {",
- " @Provides static String string() {",
- " return \"child string\";",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContainingMatch(
- "(?s)\\Qjava.lang.String cannot be provided\\E.*\\QChild.needsString()\\E")
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-
- @Test
- public void multibindingContributionBetweenAncestorComponentAndEntrypointComponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "Parent",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "Child",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface Child {",
- " Grandchild grandchild();",
- "}");
- JavaFileObject grandchild =
- JavaFileObjects.forSourceLines(
- "Grandchild",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Grandchild {",
- " Object object();",
- "}");
-
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "ParentModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.Set;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides static Object dependsOnSet(Set<String> strings) {",
- " return \"needs strings: \" + strings;",
- " }",
- "",
- " @Provides @IntoSet static String contributesToSet() {",
- " return \"parent string\";",
- " }",
- "",
- " @Provides int missingDependency(double dub) {",
- " return 4;",
- " }",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "ChildModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Module",
- "class ChildModule {",
- " @Provides @IntoSet static String contributesToSet(int i) {",
- " return \"\" + i;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().compile(parent, parentModule, child, childModule, grandchild);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContainingMatch(
- "(?s)\\Qjava.lang.Double cannot be provided\\E.*"
- + "\\QGrandchild.object() [Parent → Child → Grandchild]\\E$")
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-
- @Test
- public void manyDependencies() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Object object();",
- " String string();",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "abstract class TestModule {",
- " @Binds abstract Object object(NotBound notBound);",
- "",
- " @Provides static String string(NotBound notBound, Object object) {",
- " return notBound.toString();",
- " }",
- "}");
- JavaFileObject notBound =
- JavaFileObjects.forSourceLines(
- "test.NotBound", //
- "package test;",
- "",
- "interface NotBound {}");
- Compilation compilation = daggerCompiler().compile(component, module, notBound);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "[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:",
- " test.TestModule.string(notBound, …)",
- "The following other entry points also depend on it:",
- " test.TestComponent.string()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- assertThat(compilation).hadErrorCount(1);
- }
-
- @Test
- public void tooManyRequests() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class Foo {",
- " @Inject Foo(",
- " String one,",
- " String two,",
- " String three,",
- " String four,",
- " String five,",
- " String six,",
- " String seven,",
- " String eight,",
- " String nine,",
- " String ten,",
- " String eleven,",
- " String twelve,",
- " String thirteen) {",
- " }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " String string();",
- " Foo foo();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(foo, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "[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:",
- " 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");
- }
-
- @Test
- public void tooManyEntryPoints() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " String string1();",
- " String string2();",
- " String string3();",
- " String string4();",
- " String string5();",
- " String string6();",
- " String string7();",
- " String string8();",
- " String string9();",
- " String string10();",
- " String string11();",
- " String string12();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "[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:",
- " 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");
- }
-}
diff --git a/javatests/dagger/internal/codegen/ModelTest.java b/javatests/dagger/internal/codegen/ModelTest.java
deleted file mode 100644
index ee4cf47..0000000
--- a/javatests/dagger/internal/codegen/ModelTest.java
+++ /dev/null
@@ -1,77 +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.model.testing.BindingGraphSubject.assertThat;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.model.BindingGraph;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ModelTest {
-
- @Test
- public void cycleTest() {
- JavaFileObject a =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject A(B b) {}",
- "}");
- JavaFileObject b =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "final class B {",
- " @Inject B(Provider<A> a) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " A a();",
- "}");
-
- BindingGraphCapturer capturer = new BindingGraphCapturer();
- Compilation compilation =
- javac().withProcessors(ComponentProcessor.forTesting(capturer)).compile(a, b, component);
- assertThat(compilation).succeeded();
- BindingGraph bindingGraph = capturer.bindingGraphs().get("test.TestComponent");
- assertThat(bindingGraph).bindingWithKey("test.A").dependsOnBindingWithKey("test.B");
- assertThat(bindingGraph).bindingWithKey("test.B").dependsOnBindingWithKey("test.A");
- }
-}
diff --git a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
deleted file mode 100644
index 50c41ed..0000000
--- a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
+++ /dev/null
@@ -1,1552 +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;
-
-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 com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
-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_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;
-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 ModuleFactoryGeneratorTest {
-
- private static final JavaFileObject NULLABLE =
- JavaFileObjects.forSourceLines(
- "test.Nullable", "package test;", "public @interface Nullable {}");
-
- // TODO(gak): add tests for invalid combinations of scope and qualifier annotations like we have
- // for @Inject
-
- @Test public void providesMethodNotInModule() {
- assertThatMethodInUnannotatedClass("@Provides String provideString() { return null; }")
- .hasError("@Provides methods can only be present within a @Module or @ProducerModule");
- }
-
- @Test public void providesMethodAbstract() {
- assertThatModuleMethod("@Provides abstract String abstractMethod();")
- .hasError("@Provides methods cannot be abstract");
- }
-
- @Test public void providesMethodPrivate() {
- assertThatModuleMethod("@Provides private String privateMethod() { return null; }")
- .hasError("@Provides methods cannot be private");
- }
-
- @Test public void providesMethodReturnVoid() {
- assertThatModuleMethod("@Provides void voidMethod() {}")
- .hasError("@Provides methods must return a value (not void)");
- }
-
- @Test
- public void providesMethodReturnsProvider() {
- assertThatModuleMethod("@Provides Provider<String> provideProvider() {}")
- .hasError("@Provides methods must not return framework types");
- }
-
- @Test
- public void providesMethodReturnsLazy() {
- assertThatModuleMethod("@Provides Lazy<String> provideLazy() {}")
- .hasError("@Provides methods must not return framework types");
- }
-
- @Test
- public void providesMethodReturnsMembersInjector() {
- assertThatModuleMethod("@Provides MembersInjector<String> provideMembersInjector() {}")
- .hasError("@Provides methods must not return framework types");
- }
-
- @Test
- public void providesMethodReturnsProducer() {
- assertThatModuleMethod("@Provides Producer<String> provideProducer() {}")
- .hasError("@Provides methods must not return framework types");
- }
-
- @Test
- public void providesMethodReturnsProduced() {
- assertThatModuleMethod("@Provides Produced<String> provideProduced() {}")
- .hasError("@Provides methods must not return framework types");
- }
-
- @Test public void providesMethodWithTypeParameter() {
- assertThatModuleMethod("@Provides <T> String typeParameter() { return null; }")
- .hasError("@Provides methods may not have type parameters");
- }
-
- @Test public void providesMethodSetValuesWildcard() {
- assertThatModuleMethod("@Provides @ElementsIntoSet Set<?> provideWildcard() { return null; }")
- .hasError(
- "@Provides methods must return a primitive, an array, a type variable, "
- + "or a declared type");
- }
-
- @Test public void providesMethodSetValuesRawSet() {
- assertThatModuleMethod("@Provides @ElementsIntoSet Set provideSomething() { return null; }")
- .hasError("@Provides methods annotated with @ElementsIntoSet cannot return a raw Set");
- }
-
- @Test public void providesMethodSetValuesNotASet() {
- assertThatModuleMethod(
- "@Provides @ElementsIntoSet List<String> provideStrings() { return null; }")
- .hasError("@Provides methods annotated with @ElementsIntoSet must return a Set");
- }
-
- @Test public void modulesWithTypeParamsMustBeAbstract() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class TestModule<A> {}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Modules with type parameters must be abstract")
- .inFile(moduleFile)
- .onLine(6);
- }
-
- @Test public void provideOverriddenByNoProvide() {
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class Parent {",
- " @Provides String foo() { return null; }",
- "}");
- assertThatModuleMethod("String foo() { return null; }")
- .withDeclaration("@Module class %s extends Parent { %s }")
- .withAdditionalSources(parent)
- .hasError(
- "Binding methods may not be overridden in modules. Overrides: "
- + "@Provides String test.Parent.foo()");
- }
-
- @Test public void provideOverriddenByProvide() {
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class Parent {",
- " @Provides String foo() { return null; }",
- "}");
- assertThatModuleMethod("@Provides String foo() { return null; }")
- .withDeclaration("@Module class %s extends Parent { %s }")
- .withAdditionalSources(parent)
- .hasError(
- "Binding methods may not override another method. Overrides: "
- + "@Provides String test.Parent.foo()");
- }
-
- @Test public void providesOverridesNonProvides() {
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "class Parent {",
- " String foo() { return null; }",
- "}");
- assertThatModuleMethod("@Provides String foo() { return null; }")
- .withDeclaration("@Module class %s extends Parent { %s }")
- .withAdditionalSources(parent)
- .hasError(
- "Binding methods may not override another method. Overrides: "
- + "String test.Parent.foo()");
- }
-
- @Test public void validatesIncludedModules() {
- JavaFileObject module = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = Void.class)",
- "class TestModule {}");
-
- Compilation compilation = daggerCompiler().compile(module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.lang.Void is listed as a module, but is not annotated with @Module");
- }
-
- @Test public void singleProvidesMethodNoArgs() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String provideString() {",
- " return \"\";",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideStringFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideStringFactory implements Factory<String> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideStringFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override public String get() {",
- " return provideString(module);",
- " }",
- "",
- " public static TestModule_ProvideStringFactory create(TestModule module) {",
- " return new TestModule_ProvideStringFactory(module);",
- " }",
- "",
- " public static String provideString(TestModule instance) {",
- " return Preconditions.checkNotNull(",
- " instance.provideString(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- assertAbout(javaSource()).that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void singleProvidesMethodNoArgs_disableNullable() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String provideString() {",
- " return \"\";",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideStringFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideStringFactory implements Factory<String> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideStringFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override public String get() {",
- " return provideString(module);",
- " }",
- "",
- " public static TestModule_ProvideStringFactory create(TestModule module) {",
- " return new TestModule_ProvideStringFactory(module);",
- " }",
- "",
- " public static String provideString(TestModule instance) {",
- " return instance.provideString();",
- " }",
- "}");
- assertAbout(javaSource()).that(moduleFile)
- .withCompilerOptions("-Adagger.nullableValidation=WARNING")
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void nullableProvides() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides @Nullable String provideString() { return null; }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideStringFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideStringFactory implements Factory<String> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideStringFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override",
- " @Nullable",
- " public String get() {",
- " return provideString(module);",
- " }",
- "",
- " public static TestModule_ProvideStringFactory create(TestModule module) {",
- " return new TestModule_ProvideStringFactory(module);",
- " }",
- "",
- " @Nullable",
- " public static String provideString(TestModule instance) {",
- " return instance.provideString();",
- " }",
- "}");
- assertAbout(javaSources()).that(ImmutableList.of(moduleFile, NULLABLE))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void multipleProvidesMethods() {
- JavaFileObject classXFile = JavaFileObjects.forSourceLines("test.X",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class X {",
- " @Inject public String s;",
- "}");
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.Arrays;",
- "import java.util.List;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides List<Object> provideObjects(",
- " @QualifierA Object a, @QualifierB Object b, MembersInjector<X> xInjector) {",
- " return Arrays.asList(a, b);",
- " }",
- "",
- " @Provides @QualifierA Object provideAObject() {",
- " return new Object();",
- " }",
- "",
- " @Provides @QualifierB Object provideBObject() {",
- " return new Object();",
- " }",
- "}");
- JavaFileObject listFactoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideObjectsFactory",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- "import java.util.List;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideObjectsFactory",
- " implements Factory<List<Object>> {",
- " private final TestModule module;",
- " private final Provider<Object> aProvider;",
- " private final Provider<Object> bProvider;",
- " private final Provider<MembersInjector<X>> xInjectorProvider;",
- "",
- " public TestModule_ProvideObjectsFactory(",
- " TestModule module,",
- " Provider<Object> aProvider,",
- " Provider<Object> bProvider,",
- " Provider<MembersInjector<X>> xInjectorProvider) {",
- " this.module = module;",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " this.xInjectorProvider = xInjectorProvider;",
- " }",
- "",
- " @Override public List<Object> get() {",
- " return provideObjects(",
- " module, aProvider.get(), bProvider.get(), xInjectorProvider.get());",
- " }",
- "",
- " public static TestModule_ProvideObjectsFactory create(",
- " TestModule module,",
- " Provider<Object> aProvider,",
- " Provider<Object> bProvider,",
- " Provider<MembersInjector<X>> xInjectorProvider) {",
- " return new TestModule_ProvideObjectsFactory(",
- " module, aProvider, bProvider, xInjectorProvider);",
- " }",
- "",
- " public static List<Object> provideObjects(",
- " TestModule instance, Object a, Object b, MembersInjector<X> xInjector) {",
- " return Preconditions.checkNotNull(",
- " instance.provideObjects(a, b, xInjector), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- assertAbout(javaSources()).that(
- ImmutableList.of(classXFile, moduleFile, QUALIFIER_A, QUALIFIER_B))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(listFactoryFile);
- }
-
- @Test public void providesSetElement() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import java.util.logging.Logger;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides @IntoSet String provideString() {",
- " return \"\";",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideStringFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideStringFactory implements Factory<String> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideStringFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override public String get() {",
- " return provideString(module);",
- " }",
- "",
- " public static TestModule_ProvideStringFactory create(TestModule module) {",
- " return new TestModule_ProvideStringFactory(module);",
- " }",
- "",
- " public static String provideString(TestModule instance) {",
- " return Preconditions.checkNotNull(instance.provideString(), "
- + NPE_FROM_PROVIDES_METHOD
- + ");",
- " }",
- "}");
- assertAbout(javaSource()).that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void providesSetElementWildcard() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import java.util.logging.Logger;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import java.util.ArrayList;",
- "import java.util.List;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides @IntoSet List<List<?>> provideWildcardList() {",
- " return new ArrayList<>();",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideWildcardListFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- "import java.util.List;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideWildcardListFactory implements "
- + "Factory<List<List<?>>> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideWildcardListFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override public List<List<?>> get() {",
- " return provideWildcardList(module);",
- " }",
- "",
- " public static TestModule_ProvideWildcardListFactory create(TestModule module) {",
- " return new TestModule_ProvideWildcardListFactory(module);",
- " }",
- "",
- " public static List<List<?>> provideWildcardList(TestModule instance) {",
- " return Preconditions.checkNotNull(",
- " instance.provideWildcardList(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- assertAbout(javaSource()).that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void providesSetValues() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import java.util.Set;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides @ElementsIntoSet Set<String> provideStrings() {",
- " return null;",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProvideStringsFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- "import java.util.Set;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {",
- " private final TestModule module;",
- "",
- " public TestModule_ProvideStringsFactory(TestModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override public Set<String> get() {",
- " return provideStrings(module);",
- " }",
- "",
- " public static TestModule_ProvideStringsFactory create(TestModule module) {",
- " return new TestModule_ProvideStringsFactory(module);",
- " }",
- "",
- " public static Set<String> provideStrings(TestModule instance) {",
- " return Preconditions.checkNotNull(",
- " instance.provideStrings(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- assertAbout(javaSource()).that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and().generatesSources(factoryFile);
- }
-
- @Test public void multipleProvidesMethodsWithSameName() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides Object provide(int i) {",
- " return i;",
- " }",
- "",
- " @Provides String provide() {",
- " return \"\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot have more than one binding method with the same name in a single module")
- .inFile(moduleFile)
- .onLine(8);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot have more than one binding method with the same name in a single module")
- .inFile(moduleFile)
- .onLine(12);
- }
-
- @Test
- public void providesMethodThrowsChecked() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides int i() throws Exception {",
- " return 0;",
- " }",
- "",
- " @Provides String s() throws Throwable {",
- " return \"\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Provides methods may only throw unchecked exceptions")
- .inFile(moduleFile)
- .onLine(8);
- assertThat(compilation)
- .hadErrorContaining("@Provides methods may only throw unchecked exceptions")
- .inFile(moduleFile)
- .onLine(12);
- }
-
- @Test
- public void providedTypes() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.io.Closeable;",
- "import java.util.Set;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String string() {",
- " return null;",
- " }",
- "",
- " @Provides Set<String> strings() {",
- " return null;",
- " }",
- "",
- " @Provides Set<? extends Closeable> closeables() {",
- " return null;",
- " }",
- "",
- " @Provides String[] stringArray() {",
- " return null;",
- " }",
- "",
- " @Provides int integer() {",
- " return 0;",
- " }",
- "",
- " @Provides int[] integers() {",
- " return null;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void privateModule() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "final class Enclosing {",
- " @Module private static final class PrivateModule {",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Modules cannot be private")
- .inFile(moduleFile)
- .onLine(6);
- }
-
- @Test
- public void enclosedInPrivateModule() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "final class Enclosing {",
- " private static final class PrivateEnclosing {",
- " @Module static final class TestModule {",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Modules cannot be enclosed in private types")
- .inFile(moduleFile)
- .onLine(7);
- }
-
- @Test
- public void publicModuleNonPublicIncludes() {
- JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = {",
- " BadNonPublicModule.class, OtherPublicModule.class, OkNonPublicModule.class",
- "})",
- "public final class PublicModule {",
- "}");
- JavaFileObject badNonPublicModuleFile =
- JavaFileObjects.forSourceLines(
- "test.BadNonPublicModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class BadNonPublicModule {",
- " @Provides",
- " int provideInt() {",
- " return 42;",
- " }",
- "}");
- JavaFileObject okNonPublicModuleFile = JavaFileObjects.forSourceLines("test.OkNonPublicModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class OkNonPublicModule {",
- " @Provides",
- " static String provideString() {",
- " return \"foo\";",
- " }",
- "}");
- JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "public final class OtherPublicModule {",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(
- publicModuleFile,
- badNonPublicModuleFile,
- okNonPublicModuleFile,
- otherPublicModuleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "This module is public, but it includes non-public (or effectively non-public) modules "
- + "(test.BadNonPublicModule) 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.")
- .inFile(publicModuleFile)
- .onLine(8);
- }
-
- @Test
- public void genericSubclassedModule() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.List;",
- "import java.util.ArrayList;",
- "",
- "@Module",
- "abstract class ParentModule<A extends CharSequence,",
- " B,",
- " C extends Number & Comparable<C>> {",
- " @Provides List<B> provideListB(B b) {",
- " List<B> list = new ArrayList<B>();",
- " list.add(b);",
- " return list;",
- " }",
- "",
- " @Provides @IntoSet B provideBElement(B b) {",
- " return b;",
- " }",
- "",
- " @Provides @IntoMap @StringKey(\"b\") B provideBEntry(B b) {",
- " return b;",
- " }",
- "}");
- JavaFileObject numberChild = JavaFileObjects.forSourceLines("test.ChildNumberModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildNumberModule extends ParentModule<String, Number, Double> {",
- " @Provides Number provideNumber() { return 1; }",
- "}");
- JavaFileObject integerChild = JavaFileObjects.forSourceLines("test.ChildIntegerModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildIntegerModule extends ParentModule<StringBuilder, Integer, Float> {",
- " @Provides Integer provideInteger() { return 2; }",
- "}");
- JavaFileObject component = JavaFileObjects.forSourceLines("test.C",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.List;",
- "",
- "@Component(modules={ChildNumberModule.class, ChildIntegerModule.class})",
- "interface C {",
- " List<Number> numberList();",
- " List<Integer> integerList();",
- "}");
- JavaFileObject listBFactory =
- JavaFileObjects.forSourceLines(
- "test.ParentModule_ProvideListBFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- "import java.util.List;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- 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;",
- " private final Provider<B> bProvider;",
- "",
- " public ParentModule_ProvideListBFactory(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " this.module = module;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " @Override",
- " public List<B> get() { ",
- " return provideListB(module, bProvider.get());",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
- " ParentModule_ProvideListBFactory<A, B, C> create(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " return new ParentModule_ProvideListBFactory<A, B, C>(module, bProvider);",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>> List<B>",
- " provideListB(ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNull(",
- " instance.provideListB(b), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- JavaFileObject bElementFactory =
- JavaFileObjects.forSourceLines(
- "test.ParentModule_ProvideBElementFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- 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;",
- " private final Provider<B> bProvider;",
- "",
- " public ParentModule_ProvideBElementFactory(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " this.module = module;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " @Override",
- " public B get() { ",
- " return provideBElement(module, bProvider.get());",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
- " ParentModule_ProvideBElementFactory<A, B, C> create(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " return new ParentModule_ProvideBElementFactory<A, B, C>(module, bProvider);",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
- " B provideBElement(",
- " ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNull(",
- " instance.provideBElement(b), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- JavaFileObject bEntryFactory =
- JavaFileObjects.forSourceLines(
- "test.ParentModule_ProvideBEntryFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- 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;",
- " private final Provider<B> bProvider;",
- "",
- " public ParentModule_ProvideBEntryFactory(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " this.module = module;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " @Override",
- " public B get() { ",
- " return provideBEntry(module, bProvider.get());",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
- " ParentModule_ProvideBEntryFactory<A, B, C> create(",
- " ParentModule<A, B, C> module, Provider<B> bProvider) {",
- " return new ParentModule_ProvideBEntryFactory<A, B, C>(module, bProvider);",
- " }",
- "",
- " public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
- " B provideBEntry(",
- " ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNull(",
- " instance.provideBEntry(b), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- JavaFileObject numberFactory =
- JavaFileObjects.forSourceLines(
- "test.ChildNumberModule_ProvideNumberFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class ChildNumberModule_ProvideNumberFactory",
- " implements Factory<Number> {",
- " private final ChildNumberModule module;",
- "",
- " public ChildNumberModule_ProvideNumberFactory(ChildNumberModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override",
- " public Number get() { ",
- " return provideNumber(module);",
- " }",
- "",
- " public static ChildNumberModule_ProvideNumberFactory create(",
- " ChildNumberModule module) {",
- " return new ChildNumberModule_ProvideNumberFactory(module);",
- " }",
- "",
- " public static Number provideNumber(ChildNumberModule instance) {",
- " return Preconditions.checkNotNull(",
- " instance.provideNumber(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- JavaFileObject integerFactory =
- JavaFileObjects.forSourceLines(
- "test.ChildIntegerModule_ProvideIntegerFactory",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "public final class ChildIntegerModule_ProvideIntegerFactory",
- " implements Factory<Integer> {",
- " private final ChildIntegerModule module;",
- "",
- " public ChildIntegerModule_ProvideIntegerFactory(ChildIntegerModule module) {",
- " this.module = module;",
- " }",
- "",
- " @Override",
- " public Integer get() { ",
- " return provideInteger(module);",
- " }",
- "",
- " public static ChildIntegerModule_ProvideIntegerFactory create(",
- " ChildIntegerModule module) {",
- " return new ChildIntegerModule_ProvideIntegerFactory(module);",
- " }",
- "",
- " public static Integer provideInteger(ChildIntegerModule instance) {",
- " return Preconditions.checkNotNull(",
- " instance.provideInteger(), " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
- assertAbout(javaSources())
- .that(ImmutableList.of(parent, numberChild, integerChild, component))
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(
- listBFactory, bElementFactory, bEntryFactory, numberFactory, integerFactory);
- }
-
- @Test public void parameterizedModuleWithStaticProvidesMethodOfGenericType() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.ParameterizedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.List;",
- "import java.util.ArrayList;",
- "import java.util.Map;",
- "import java.util.HashMap;",
- "",
- "@Module abstract class ParameterizedModule<T> {",
- " @Provides List<T> provideListT() {",
- " return new ArrayList<>();",
- " }",
- "",
- " @Provides static Map<String, Number> provideMapStringNumber() {",
- " return new HashMap<>();",
- " }",
- "",
- " @Provides static Object provideNonGenericType() {",
- " return new Object();",
- " }",
- "",
- " @Provides static String provideNonGenericTypeWithDeps(Object o) {",
- " return o.toString();",
- " }",
- "}");
-
- JavaFileObject provideMapStringNumberFactory =
- JavaFileObjects.forSourceLines(
- "test.ParameterizedModule_ProvideMapStringNumberFactory;",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- "import java.util.Map;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- 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 INSTANCE;",
- " }",
- "",
- " public static Map<String, Number> provideMapStringNumber() {",
- " return Preconditions.checkNotNull(ParameterizedModule.provideMapStringNumber(),",
- " " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
-
- JavaFileObject provideNonGenericTypeFactory =
- JavaFileObjects.forSourceLines(
- "test.ParameterizedModule_ProvideNonGenericTypeFactory;",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- 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 INSTANCE;",
- " }",
- "",
- " public static Object provideNonGenericType() {",
- " return Preconditions.checkNotNull(ParameterizedModule.provideNonGenericType(),",
- " " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
-
- JavaFileObject provideNonGenericTypeWithDepsFactory =
- JavaFileObjects.forSourceLines(
- "test.ParameterizedModule_ProvideNonGenericTypeWithDepsFactory;",
- "package test;",
- "",
- "import dagger.internal.Factory;",
- "import dagger.internal.Preconditions;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class ParameterizedModule_ProvideNonGenericTypeWithDepsFactory",
- " implements Factory<String> {",
- " private final Provider<Object> oProvider;",
- "",
- " public ParameterizedModule_ProvideNonGenericTypeWithDepsFactory(",
- " Provider<Object> oProvider) {",
- " this.oProvider = oProvider;",
- " }",
- "",
- " @Override",
- " public String get() {",
- " return provideNonGenericTypeWithDeps(oProvider.get());",
- " }",
- "",
- " public static ParameterizedModule_ProvideNonGenericTypeWithDepsFactory create(",
- " Provider<Object> oProvider) {",
- " return new ParameterizedModule_ProvideNonGenericTypeWithDepsFactory(oProvider);",
- " }",
- "",
- " public static String provideNonGenericTypeWithDeps(Object o) {",
- " return Preconditions.checkNotNull(",
- " ParameterizedModule.provideNonGenericTypeWithDeps(o),",
- " " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- "}");
-
- assertAbout(javaSource())
- .that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(
- provideMapStringNumberFactory,
- provideNonGenericTypeFactory,
- provideNonGenericTypeWithDepsFactory);
- }
-
- private static final JavaFileObject QUALIFIER_A =
- JavaFileObjects.forSourceLines(
- "test.QualifierA",
- "package test;",
- "",
- "import javax.inject.Qualifier;",
- "",
- "@Qualifier @interface QualifierA {}");
-
- private static final JavaFileObject QUALIFIER_B =
- JavaFileObjects.forSourceLines(
- "test.QualifierB",
- "package test;",
- "",
- "import javax.inject.Qualifier;",
- "",
- "@Qualifier @interface QualifierB {}");
-
- @Test
- public void providesMethodMultipleQualifiersOnMethod() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides @QualifierA @QualifierB String provideString() {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("may not use more than one @Qualifier");
- }
-
- @Test
- public void providesMethodMultipleQualifiersOnParameter() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides static String provideString(@QualifierA @QualifierB Object object) {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("may not use more than one @Qualifier");
- }
-
- @Test
- public void providesMethodWildcardDependency() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Provider;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides static String provideString(Provider<? extends Number> numberProvider) {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile, QUALIFIER_A, QUALIFIER_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, or Produced<T> "
- + "when T is a wildcard type such as ? extends java.lang.Number");
- }
-
- private static final JavaFileObject SCOPE_A =
- JavaFileObjects.forSourceLines(
- "test.ScopeA",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeA {}");
-
- private static final JavaFileObject SCOPE_B =
- JavaFileObjects.forSourceLines(
- "test.ScopeB",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeB {}");
-
- @Test
- public void providesMethodMultipleScopes() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides",
- " @ScopeA",
- " @ScopeB",
- " String provideString() {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile, SCOPE_A, SCOPE_B);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cannot use more than one @Scope")
- .inFile(moduleFile)
- .onLineContaining("@ScopeA");
- assertThat(compilation)
- .hadErrorContaining("cannot use more than one @Scope")
- .inFile(moduleFile)
- .onLineContaining("@ScopeB");
- }
-
- @Test public void providerDependsOnProduced() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.producers.Producer;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String provideString(Producer<Integer> producer) {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Producer may only be injected in @Produces methods");
- }
-
- @Test public void providerDependsOnProducer() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.producers.Produced;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String provideString(Produced<Integer> produced) {",
- " return \"foo\";",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Produced may only be injected in @Produces methods");
- }
-
- @Test
- public void proxyMethodsConflictWithOtherFactoryMethods() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static int get() { return 1; }",
- "",
- " @Provides",
- " static boolean create() { return true; }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(module);
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.TestModule_GetFactory")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.TestModule_GetFactory",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_GetFactory implements Factory<Integer> {",
- " @Override",
- " public Integer get() {",
- " return proxyGet();",
- " }",
- "",
- " public static TestModule_GetFactory create() {",
- " return INSTANCE;",
- " }",
- "",
- " public static int proxyGet() {",
- " return TestModule.get();",
- " }",
- "}"));
-
- assertThat(compilation)
- .generatedSourceFile("test.TestModule_CreateFactory")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.TestModule_CreateFactory",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "public final class TestModule_CreateFactory implements Factory<Boolean> {",
- " @Override",
- " public Boolean get() {",
- " return proxyCreate();",
- " }",
- "",
- " public static TestModule_CreateFactory create() {",
- " return INSTANCE;",
- " }",
- "",
- " public static boolean proxyCreate() {",
- " return TestModule.create();",
- " }",
- "}"));
- }
-
- private static final String BINDS_METHOD = "@Binds abstract Foo bindFoo(FooImpl impl);";
- private static final String MULTIBINDS_METHOD = "@Multibinds abstract Set<Foo> foos();";
- private static final String STATIC_PROVIDES_METHOD =
- "@Provides static Bar provideBar() { return new Bar(); }";
- private static final String INSTANCE_PROVIDES_METHOD =
- "@Provides Baz provideBaz() { return new Baz(); }";
- private static final String SOME_ABSTRACT_METHOD = "abstract void blah();";
-
- @Test
- public void bindsWithInstanceProvides() {
- Compilation compilation = compileMethodCombination(BINDS_METHOD, INSTANCE_PROVIDES_METHOD);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "A @Module may not contain both non-static and abstract binding methods");
- }
-
- @Test
- public void multibindsWithInstanceProvides() {
- Compilation compilation = compileMethodCombination(MULTIBINDS_METHOD, INSTANCE_PROVIDES_METHOD);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "A @Module may not contain both non-static and abstract binding methods");
- }
-
- @Test
- public void bindsWithStaticProvides() {
- assertThat(compileMethodCombination(BINDS_METHOD, STATIC_PROVIDES_METHOD)).succeeded();
- }
-
- @Test
- public void bindsWithMultibinds() {
- assertThat(compileMethodCombination(BINDS_METHOD, MULTIBINDS_METHOD)).succeeded();
- }
-
- @Test
- public void multibindsWithStaticProvides() {
- assertThat(compileMethodCombination(MULTIBINDS_METHOD, STATIC_PROVIDES_METHOD)).succeeded();
- }
-
- @Test
- public void instanceProvidesWithAbstractMethod() {
- assertThat(compileMethodCombination(INSTANCE_PROVIDES_METHOD, SOME_ABSTRACT_METHOD))
- .succeeded();
- }
-
- private Compilation compileMethodCombination(String... methodLines) {
- JavaFileObject fooFile =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "interface Foo {}");
- JavaFileObject fooImplFile =
- JavaFileObjects.forSourceLines(
- "test.FooImpl",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class FooImpl implements Foo {",
- " @Inject FooImpl() {}",
- "}");
- JavaFileObject barFile =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "final class Bar {}");
- JavaFileObject bazFile =
- JavaFileObjects.forSourceLines(
- "test.Baz",
- "package test;",
- "",
- "final class Baz {}");
-
- ImmutableList<String> moduleLines =
- new ImmutableList.Builder<String>()
- .add(
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Set;",
- "",
- "@Module abstract class TestModule {")
- .add(methodLines)
- .add("}")
- .build();
-
- JavaFileObject bindsMethodAndInstanceProvidesMethodModuleFile =
- JavaFileObjects.forSourceLines("test.TestModule", moduleLines);
- return daggerCompiler()
- .compile(
- fooFile, fooImplFile, barFile, bazFile, bindsMethodAndInstanceProvidesMethodModuleFile);
- }
-}
diff --git a/javatests/dagger/internal/codegen/ModuleValidationTest.java b/javatests/dagger/internal/codegen/ModuleValidationTest.java
deleted file mode 100644
index 649649a..0000000
--- a/javatests/dagger/internal/codegen/ModuleValidationTest.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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
-import java.util.Arrays;
-import java.util.Collection;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public final class ModuleValidationTest {
-
- @Parameterized.Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return Arrays.asList(new Object[][] {{ModuleType.MODULE}, {ModuleType.PRODUCER_MODULE}});
- }
-
- private enum ModuleType {
- MODULE(Module.class),
- PRODUCER_MODULE(ProducerModule.class),
- ;
-
- private final Class<? extends Annotation> annotation;
-
- ModuleType(Class<? extends Annotation> annotation) {
- this.annotation = annotation;
- }
-
- String annotationWithSubcomponent(String subcomponent) {
- return String.format("@%s(subcomponents = %s)", annotation.getSimpleName(), subcomponent);
- }
-
- String importStatement() {
- return String.format("import %s;", annotation.getName());
- }
-
- String simpleName() {
- return annotation.getSimpleName();
- }
- }
-
- private final ModuleType moduleType;
-
- public ModuleValidationTest(ModuleType moduleType) {
- this.moduleType = moduleType;
- }
-
- @Test
- public void moduleSubcomponents_notASubcomponent() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("NotASubcomponent.class"),
- "class TestModule {}");
- JavaFileObject notASubcomponent =
- JavaFileObjects.forSourceLines(
- "test.NotASubcomponent", "package test;", "", "class NotASubcomponent {}");
- Compilation compilation = daggerCompiler().compile(module, notASubcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.NotASubcomponent is not a @Subcomponent or @ProductionSubcomponent")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_listsSubcomponentBuilder() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("Sub.Builder.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Sub.Builder is a @Subcomponent.Builder. Did you mean to use test.Sub?")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_listsSubcomponentFactory() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("Sub.Factory.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " @Subcomponent.Factory",
- " interface Factory {",
- " Sub creator();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Sub.Factory is a @Subcomponent.Factory. Did you mean to use test.Sub?")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_listsProductionSubcomponentBuilder() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("Sub.Builder.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent",
- "interface Sub {",
- " @ProductionSubcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Sub.Builder is a @ProductionSubcomponent.Builder. Did you mean to use test.Sub?")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_listsProductionSubcomponentFactory() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("Sub.Factory.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent",
- "interface Sub {",
- " @ProductionSubcomponent.Factory",
- " interface Factory {",
- " Sub create();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Sub.Factory is a @ProductionSubcomponent.Factory. Did you mean to use test.Sub?")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_noSubcomponentCreator() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("NoBuilder.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.NoBuilder",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface NoBuilder {}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.NoBuilder doesn't have a @Subcomponent.Builder or @Subcomponent.Factory, which "
- + "is required when used with @"
- + moduleType.simpleName()
- + ".subcomponents")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponents_noProductionSubcomponentCreator() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "",
- moduleType.annotationWithSubcomponent("NoBuilder.class"),
- "class TestModule {}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.NoBuilder",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent",
- "interface NoBuilder {}");
- Compilation compilation = daggerCompiler().compile(module, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.NoBuilder doesn't have a @ProductionSubcomponent.Builder or "
- + "@ProductionSubcomponent.Factory, which is required when used with @"
- + moduleType.simpleName()
- + ".subcomponents")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void moduleSubcomponentsAreTypes() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(subcomponents = int.class)",
- "class TestModule {}");
- Compilation compilation = daggerCompiler().compile(module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("int is not a valid subcomponent type")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void tooManyAnnotations() {
- assertThatModuleMethod(
- "@BindsOptionalOf @Multibinds abstract Set<Object> tooManyAnnotations();")
- .hasError("is annotated with more than one of");
- }
-
- @Test
- public void invalidIncludedModule() {
- JavaFileObject badModule =
- JavaFileObjects.forSourceLines(
- "test.BadModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "abstract class BadModule {",
- " @Binds abstract Object noParameters();",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.IncludesBadModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(includes = BadModule.class)",
- "abstract class IncludesBadModule {}");
- assertThat(daggerCompiler().compile(badModule, module))
- .hadErrorContaining("test.BadModule has errors")
- .inFile(module)
- .onLine(5);
- }
-
- @Test
- public void scopeOnModule() {
- JavaFileObject badModule =
- JavaFileObjects.forSourceLines(
- "test.BadModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Module",
- "interface BadModule {}");
- Compilation compilation = daggerCompiler().compile(badModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Modules cannot be scoped")
- .inFile(badModule)
- .onLineContaining("@Singleton");
- }
-
- @Test
- public void moduleIncludesSelfCycle() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- moduleType.importStatement(),
- "import dagger.Provides;",
- "",
- String.format("@%s(", moduleType.simpleName()),
- " includes = {",
- " TestModule.class, // first",
- " OtherModule.class,",
- " TestModule.class, // second",
- " }",
- ")",
- "class TestModule {",
- " @Provides int i() { return 0; }",
- "}");
-
- JavaFileObject otherModule =
- JavaFileObjects.forSourceLines(
- "test.OtherModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "class OtherModule {}");
-
- Compilation compilation = daggerCompiler().compile(module, otherModule);
- assertThat(compilation).failed();
- String error = String.format("@%s cannot include themselves", moduleType.simpleName());
- assertThat(compilation).hadErrorContaining(error).inFile(module).onLineContaining("Module(");
- }
-}
diff --git a/javatests/dagger/internal/codegen/MultibindingTest.java b/javatests/dagger/internal/codegen/MultibindingTest.java
deleted file mode 100644
index 2bf9494..0000000
--- a/javatests/dagger/internal/codegen/MultibindingTest.java
+++ /dev/null
@@ -1,262 +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;
-
-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 class MultibindingTest {
-
- @Test
- public void providesWithTwoMultibindingAnnotations_failsToCompile() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.MultibindingModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.multibindings.IntoMap;",
- "",
- "@Module",
- "class MultibindingModule {",
- " @Provides @IntoSet @IntoMap Integer provideInt() { ",
- " return 1;",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Provides methods cannot have more than one multibinding annotation")
- .inFile(module)
- .onLine(10);
- }
-
- @Test
- public void appliedOnInvalidMethods_failsToCompile() {
- JavaFileObject someType =
- JavaFileObjects.forSourceLines(
- "test.SomeType",
- "package test;",
- "",
- "import java.util.Set;",
- "import java.util.Map;",
- "import dagger.Component;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import dagger.multibindings.IntoMap;",
- "",
- "interface SomeType {",
- " @IntoSet Set<Integer> ints();",
- " @ElementsIntoSet Set<Double> doubles();",
- " @IntoMap Map<Integer, Double> map();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(someType);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
- .inFile(someType)
- .onLineContaining("ints();");
- assertThat(compilation)
- .hadErrorContaining(
- "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
- .inFile(someType)
- .onLineContaining("doubles();");
- assertThat(compilation)
- .hadErrorContaining(
- "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
- .inFile(someType)
- .onLineContaining("map();");
- }
-
- @Test
- public void concreteBindingForMultibindingAlias() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.Collections;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Module",
- "class TestModule {",
- " @Provides",
- " Map<String, Provider<String>> mapOfStringToProviderOfString() {",
- " return Collections.emptyMap();",
- " }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Map<String, String> mapOfStringToString();",
- "}");
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Map<java.lang.String,java.lang.String> "
- + "cannot be provided without an @Provides-annotated method")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void produceConcreteSet_andRequestSetOfProduced() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@ProducerModule",
- "class TestModule {",
- " @Produces",
- " Set<String> setOfString() {",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.BindsInstance;",
- "import dagger.producers.Produced;",
- "import dagger.producers.Production;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.concurrent.Executor;",
- "import java.util.Set;",
- "",
- "@ProductionComponent(modules = TestModule.class)",
- "interface TestComponent {",
- " ListenableFuture<Set<Produced<String>>> setOfProduced();",
- "",
- " @ProductionComponent.Builder",
- " interface Builder {",
- " @BindsInstance Builder executor(@Production Executor executor);",
- " TestComponent build();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.util.Set<dagger.producers.Produced<java.lang.String>> "
- + "cannot be provided without an @Provides- or @Produces-annotated method")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void provideExplicitSetInParent_AndMultibindingContributionInChild() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Set<String> set();",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.HashSet;",
- "import java.util.Set;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides",
- " Set<String> set() {",
- " return new HashSet();",
- " }",
- "}");
-
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Set;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface Child {",
- " Set<String> set();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class ChildModule {",
- " @Provides",
- " @IntoSet",
- " String setContribution() {",
- " return new String();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("incompatible bindings or declarations")
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-}
diff --git a/javatests/dagger/internal/codegen/MultibindsValidationTest.java b/javatests/dagger/internal/codegen/MultibindsValidationTest.java
deleted file mode 100644
index e5603a4..0000000
--- a/javatests/dagger/internal/codegen/MultibindsValidationTest.java
+++ /dev/null
@@ -1,168 +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;
-
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
-
-import com.google.common.collect.ImmutableList;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import javax.inject.Qualifier;
-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 MultibindsValidationTest {
-
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return ImmutableList.copyOf(new Object[][] {{Module.class}, {ProducerModule.class}});
- }
-
- private final String moduleDeclaration;
-
- public MultibindsValidationTest(Class<? extends Annotation> moduleAnnotation) {
- moduleDeclaration = "@" + moduleAnnotation.getCanonicalName() + " abstract class %s { %s }";
- }
-
- @Test
- public void notWithinModule() {
- assertThatMethodInUnannotatedClass("@Multibinds abstract Set<Object> emptySet();")
- .hasError("@Multibinds methods can only be present within a @Module or @ProducerModule");
- }
-
- @Test
- public void voidMethod() {
- assertThatModuleMethod("@Multibinds abstract void voidMethod();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void primitiveMethod() {
- assertThatModuleMethod("@Multibinds abstract int primitive();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void rawMap() {
- assertThatModuleMethod("@Multibinds abstract Map rawMap();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void wildcardMap() {
- assertThatModuleMethod("@Multibinds abstract Map<?, ?> wildcardMap();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void providerMap() {
- assertThatModuleMethod("@Multibinds abstract Map<String, Provider<Object>> providerMap();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void producerMap() {
- assertThatModuleMethod("@Multibinds abstract Map<String, Producer<Object>> producerMap();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void producedMap() {
- assertThatModuleMethod("@Multibinds abstract Map<String, Produced<Object>> producedMap();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void rawSet() {
- assertThatModuleMethod("@Multibinds abstract Set rawSet();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void wildcardSet() {
- assertThatModuleMethod("@Multibinds abstract Set<?> wildcardSet();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void providerSet() {
- assertThatModuleMethod("@Multibinds abstract Set<Provider<Object>> providerSet();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void producerSet() {
- assertThatModuleMethod("@Multibinds abstract Set<Producer<Object>> producerSet();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void producedSet() {
- assertThatModuleMethod("@Multibinds abstract Set<Produced<Object>> producedSet();")
- .withDeclaration(moduleDeclaration)
- .hasError("@Multibinds methods must return Map<K, V> or Set<T>");
- }
-
- @Test
- public void overqualifiedSet() {
- assertThatModuleMethod(
- "@Multibinds @SomeQualifier @OtherQualifier "
- + "abstract Set<Object> tooManyQualifiersSet();")
- .withDeclaration(moduleDeclaration)
- .importing(SomeQualifier.class, OtherQualifier.class)
- .hasError("may not use more than one @Qualifier");
- }
-
- @Test
- public void overqualifiedMap() {
- assertThatModuleMethod(
- "@Multibinds @SomeQualifier @OtherQualifier "
- + "abstract Map<String, Object> tooManyQualifiersMap();")
- .withDeclaration(moduleDeclaration)
- .importing(SomeQualifier.class, OtherQualifier.class)
- .hasError("may not use more than one @Qualifier");
- }
-
- @Test
- public void hasParameters() {
- assertThatModuleMethod("@Multibinds abstract Set<String> parameters(Object param);")
- .hasError("@Multibinds methods cannot have parameters");
- }
-
- @Qualifier
- public @interface SomeQualifier {}
-
- @Qualifier
- public @interface OtherQualifier {}
-}
diff --git a/javatests/dagger/internal/codegen/MultipleRequestTest.java b/javatests/dagger/internal/codegen/MultipleRequestTest.java
deleted file mode 100644
index a5514ca..0000000
--- a/javatests/dagger/internal/codegen/MultipleRequestTest.java
+++ /dev/null
@@ -1,126 +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;
-
-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 class MultipleRequestTest {
- private static final JavaFileObject DEP_FILE = JavaFileObjects.forSourceLines("test.Dep",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Dep {",
- " @Inject Dep() {}",
- "}");
-
- @Test public void multipleRequests_constructor() {
- Compilation compilation =
- daggerCompiler()
- .compile(
- DEP_FILE,
- JavaFileObjects.forSourceLines(
- "test.ConstructorInjectsMultiple",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class ConstructorInjectsMultiple {",
- " @Inject ConstructorInjectsMultiple(Dep d1, Dep d2) {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " ConstructorInjectsMultiple get();",
- "}"));
- assertThat(compilation).succeeded();
- }
-
- @Test public void multipleRequests_field() {
- Compilation compilation =
- daggerCompiler()
- .compile(
- DEP_FILE,
- JavaFileObjects.forSourceLines(
- "test.FieldInjectsMultiple",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FieldInjectsMultiple {",
- " @Inject Dep d1;",
- " @Inject Dep d2;",
- " @Inject FieldInjectsMultiple() {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface SimpleComponent {",
- " FieldInjectsMultiple get();",
- "}"));
- assertThat(compilation).succeeded();
- }
-
- @Test public void multipleRequests_providesMethod() {
- Compilation compilation =
- daggerCompiler()
- .compile(
- DEP_FILE,
- JavaFileObjects.forSourceLines(
- "test.FieldInjectsMultiple",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class SimpleModule {",
- " @Provides Object provide(Dep d1, Dep d2) {",
- " return null;",
- " }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = SimpleModule.class)",
- "interface SimpleComponent {",
- " Object get();",
- "}"));
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/internal/codegen/NullableBindingValidationTest.java b/javatests/dagger/internal/codegen/NullableBindingValidationTest.java
deleted file mode 100644
index 24d5636..0000000
--- a/javatests/dagger/internal/codegen/NullableBindingValidationTest.java
+++ /dev/null
@@ -1,419 +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.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
deleted file mode 100644
index b765166..0000000
--- a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
+++ /dev/null
@@ -1,282 +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;
-
-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_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 OptionalBindingRequestFulfillmentTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public OptionalBindingRequestFulfillmentTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void inlinedOptionalBindings() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.BindsOptionalOf;",
- "import other.Maybe;",
- "import other.DefinitelyNot;",
- "",
- "@Module",
- "interface TestModule {",
- " @BindsOptionalOf Maybe maybe();",
- " @BindsOptionalOf DefinitelyNot definitelyNot();",
- "}");
- JavaFileObject maybe =
- JavaFileObjects.forSourceLines(
- "other.Maybe",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "public class Maybe {",
- " @Module",
- " public static class MaybeModule {",
- " @Provides static Maybe provideMaybe() { return new Maybe(); }",
- " }",
- "}");
- JavaFileObject definitelyNot =
- JavaFileObjects.forSourceLines(
- "other.DefinitelyNot",
- "package other;",
- "",
- "public class DefinitelyNot {}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import com.google.common.base.Optional;",
- "import dagger.Component;",
- "import dagger.Lazy;",
- "import javax.inject.Provider;",
- "import other.Maybe;",
- "import other.DefinitelyNot;",
- "",
- "@Component(modules = {TestModule.class, Maybe.MaybeModule.class})",
- "interface TestComponent {",
- " Optional<Maybe> maybe();",
- " Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe();",
- " Optional<DefinitelyNot> definitelyNot();",
- " Optional<Provider<Lazy<DefinitelyNot>>> providerOfLazyOfDefinitelyNot();",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines(
- "package test;",
- "",
- "import com.google.common.base.Optional;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {")
- .addLinesIn(
- FAST_INIT_MODE,
- " private volatile Provider<Maybe> provideMaybeProvider;",
- "",
- " private Provider<Maybe> getMaybeProvider() {",
- " Object local = provideMaybeProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " provideMaybeProvider = (Provider<Maybe>) local;",
- " }",
- " return (Provider<Maybe>) local;",
- " }")
- .addLines(
- " @Override",
- " public Optional<Maybe> maybe() {",
- " return Optional.of(",
- " Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe());",
- " }",
- "",
- " @Override",
- " public Optional<Provider<Lazy<Maybe>>> providerOfLazyOfMaybe() {",
- " return Optional.of(ProviderOfLazy.create(")
- .addLinesIn(
- DEFAULT_MODE, //
- " Maybe_MaybeModule_ProvideMaybeFactory.create()));")
- .addLinesIn(
- FAST_INIT_MODE, //
- " getMaybeProvider()));")
- .addLines(
- " }",
- "",
- " @Override",
- " public Optional<DefinitelyNot> definitelyNot() {",
- " return Optional.<DefinitelyNot>absent();",
- " }",
- "",
- " @Override",
- " public Optional<Provider<Lazy<DefinitelyNot>>>",
- " providerOfLazyOfDefinitelyNot() {",
- " return Optional.<Provider<Lazy<DefinitelyNot>>>absent();",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe();",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}")
- .build();
- Compilation compilation =
- compilerWithOptions(
- compilerMode
- , CompilerMode.JAVA7
- )
- .compile(module, maybe, definitelyNot, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void requestForFuture() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.BindsOptionalOf;",
- "import other.Maybe;",
- "import other.DefinitelyNot;",
- "",
- "@Module",
- "interface TestModule {",
- " @BindsOptionalOf Maybe maybe();",
- " @BindsOptionalOf DefinitelyNot definitelyNot();",
- "}");
- JavaFileObject maybe =
- JavaFileObjects.forSourceLines(
- "other.Maybe",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "public class Maybe {",
- " @Module",
- " public static class MaybeModule {",
- " @Provides static Maybe provideMaybe() { return new Maybe(); }",
- " }",
- "}");
- JavaFileObject definitelyNot =
- JavaFileObjects.forSourceLines(
- "other.DefinitelyNot",
- "package other;",
- "",
- "public class DefinitelyNot {}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import com.google.common.base.Optional;",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "import javax.inject.Provider;",
- "import other.Maybe;",
- "import other.DefinitelyNot;",
- "",
- "@ProductionComponent(modules = {TestModule.class, Maybe.MaybeModule.class})",
- "interface TestComponent {",
- " ListenableFuture<Optional<Maybe>> maybe();",
- " ListenableFuture<Optional<DefinitelyNot>> definitelyNot();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.base.Optional;",
- "import dagger.producers.internal.CancellationListener;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent, CancellationListener {",
- " @Override",
- " public ListenableFuture<Optional<Maybe>> maybe() {",
- " return Futures.immediateFuture(",
- " Optional.of(Maybe_MaybeModule_ProvideMaybeFactory.provideMaybe()));",
- " }",
- "",
- " @Override",
- " public ListenableFuture<Optional<DefinitelyNot>> definitelyNot() {",
- " return Futures.immediateFuture(Optional.<DefinitelyNot>absent());",
-
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {}",
- "}");
-
- Compilation compilation =
- compilerWithOptions(
- compilerMode
- , CompilerMode.JAVA7
- )
- .compile(module, maybe, definitelyNot, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/OptionalBindingTest.java b/javatests/dagger/internal/codegen/OptionalBindingTest.java
deleted file mode 100644
index 1755101..0000000
--- a/javatests/dagger/internal/codegen/OptionalBindingTest.java
+++ /dev/null
@@ -1,96 +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;
-
-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 class OptionalBindingTest {
- @Test
- public void provideExplicitOptionalInParent_AndBindsOptionalOfInChild() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Optional;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Optional<String> optional();",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import java.util.Optional;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides",
- " Optional<String> optional() {",
- " return Optional.of(new String());",
- " }",
- "}");
-
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Optional;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface Child {",
- " Optional<String> optional();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.BindsOptionalOf;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ChildModule {",
- " @BindsOptionalOf",
- " String optionalString();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Optional<java.lang.String> is bound multiple times")
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-}
diff --git a/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
deleted file mode 100644
index 0b6ef8f..0000000
--- a/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
+++ /dev/null
@@ -1,522 +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.
- */
-
-// TODO(beder): Merge the error-handling tests with the ModuleFactoryGeneratorTest.
-package dagger.internal.codegen;
-
-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.daggerCompiler;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
-import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatProductionModuleMethod;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ProducerModuleFactoryGeneratorTest {
-
- @Test public void producesMethodNotInModule() {
- assertThatMethodInUnannotatedClass("@Produces String produceString() { return null; }")
- .hasError("@Produces methods can only be present within a @ProducerModule");
- }
-
- @Test public void producesMethodAbstract() {
- assertThatProductionModuleMethod("@Produces abstract String produceString();")
- .hasError("@Produces methods cannot be abstract");
- }
-
- @Test public void producesMethodPrivate() {
- assertThatProductionModuleMethod("@Produces private String produceString() { return null; }")
- .hasError("@Produces methods cannot be private");
- }
-
- @Test public void producesMethodReturnVoid() {
- assertThatProductionModuleMethod("@Produces void produceNothing() {}")
- .hasError("@Produces methods must return a value (not void)");
- }
-
- @Test
- public void producesProvider() {
- assertThatProductionModuleMethod("@Produces Provider<String> produceProvider() {}")
- .hasError("@Produces methods must not return framework types");
- }
-
- @Test
- public void producesLazy() {
- assertThatProductionModuleMethod("@Produces Lazy<String> produceLazy() {}")
- .hasError("@Produces methods must not return framework types");
- }
-
- @Test
- public void producesMembersInjector() {
- assertThatProductionModuleMethod(
- "@Produces MembersInjector<String> produceMembersInjector() {}")
- .hasError("@Produces methods must not return framework types");
- }
-
- @Test
- public void producesProducer() {
- assertThatProductionModuleMethod("@Produces Producer<String> produceProducer() {}")
- .hasError("@Produces methods must not return framework types");
- }
-
- @Test
- public void producesProduced() {
- assertThatProductionModuleMethod("@Produces Produced<String> produceProduced() {}")
- .hasError("@Produces methods must not return framework types");
- }
-
- @Test public void producesMethodReturnRawFuture() {
- assertThatProductionModuleMethod("@Produces ListenableFuture produceRaw() {}")
- .importing(ListenableFuture.class)
- .hasError("@Produces methods cannot return a raw ListenableFuture");
- }
-
- @Test public void producesMethodReturnWildcardFuture() {
- assertThatProductionModuleMethod("@Produces ListenableFuture<?> produceRaw() {}")
- .importing(ListenableFuture.class)
- .hasError(
- "@Produces methods can return only a primitive, an array, a type variable, "
- + "a declared type, or a ListenableFuture of one of those types");
- }
-
- @Test public void producesMethodWithTypeParameter() {
- assertThatProductionModuleMethod("@Produces <T> String produceString() { return null; }")
- .hasError("@Produces methods may not have type parameters");
- }
-
- @Test public void producesMethodSetValuesWildcard() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet Set<?> produceWildcard() { return null; }")
- .hasError(
- "@Produces methods can return only a primitive, an array, a type variable, "
- + "a declared type, or a ListenableFuture of one of those types");
- }
-
- @Test public void producesMethodSetValuesRawSet() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet Set produceSomething() { return null; }")
- .hasError("@Produces methods annotated with @ElementsIntoSet cannot return a raw Set");
- }
-
- @Test public void producesMethodSetValuesNotASet() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet List<String> produceStrings() { return null; }")
- .hasError(
- "@Produces methods of type set values must return a Set or ListenableFuture of Set");
- }
-
- @Test public void producesMethodSetValuesWildcardInFuture() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet "
- + "ListenableFuture<Set<?>> produceWildcard() { return null; }")
- .importing(ListenableFuture.class)
- .hasError(
- "@Produces methods can return only a primitive, an array, a type variable, "
- + "a declared type, or a ListenableFuture of one of those types");
- }
-
- @Test public void producesMethodSetValuesFutureRawSet() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet ListenableFuture<Set> produceSomething() { return null; }")
- .importing(ListenableFuture.class)
- .hasError("@Produces methods annotated with @ElementsIntoSet cannot return a raw Set");
- }
-
- @Test public void producesMethodSetValuesFutureNotASet() {
- assertThatProductionModuleMethod(
- "@Produces @ElementsIntoSet "
- + "ListenableFuture<List<String>> produceStrings() { return null; }")
- .importing(ListenableFuture.class)
- .hasError(
- "@Produces methods of type set values must return a Set or ListenableFuture of Set");
- }
-
- @Test public void multipleProducesMethodsWithSameName() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "@ProducerModule",
- "final class TestModule {",
- " @Produces Object produce(int i) {",
- " return i;",
- " }",
- "",
- " @Produces String produce() {",
- " return \"\";",
- " }",
- "}");
- String errorMessage =
- "Cannot have more than one binding method with the same name in a single module";
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(errorMessage).inFile(moduleFile).onLine(8);
- assertThat(compilation).hadErrorContaining(errorMessage).inFile(moduleFile).onLine(12);
- }
-
- @Test
- public void producesMethodThrowsThrowable() {
- assertThatProductionModuleMethod("@Produces int produceInt() throws Throwable { return 0; }")
- .hasError(
- "@Produces methods may only throw unchecked exceptions or exceptions subclassing "
- + "Exception");
- }
-
- @Test public void producesMethodWithScope() {
- assertThatProductionModuleMethod("@Produces @Singleton String str() { return \"\"; }")
- .hasError("@Produces methods cannot be scoped");
- }
-
- @Test
- public void privateModule() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "final class Enclosing {",
- " @ProducerModule private static final class PrivateModule {",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Modules cannot be private")
- .inFile(moduleFile)
- .onLine(6);
- }
-
- @Test
- public void enclosedInPrivateModule() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "final class Enclosing {",
- " private static final class PrivateEnclosing {",
- " @ProducerModule static final class TestModule {",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Modules cannot be enclosed in private types")
- .inFile(moduleFile)
- .onLine(7);
- }
-
- @Test
- public void includesNonModule() {
- JavaFileObject xFile =
- JavaFileObjects.forSourceLines("test.X", "package test;", "", "public final class X {}");
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.FooModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "@ProducerModule(includes = X.class)",
- "public final class FooModule {",
- "}");
- Compilation compilation = daggerCompiler().compile(xFile, moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "X is listed as a module, but is not annotated with one of @Module, @ProducerModule");
- }
-
- // TODO(ronshapiro): merge this with the equivalent test in ModuleFactoryGeneratorTest and make it
- // parameterized
- @Test
- public void publicModuleNonPublicIncludes() {
- JavaFileObject publicModuleFile = JavaFileObjects.forSourceLines("test.PublicModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "@ProducerModule(includes = {",
- " BadNonPublicModule.class, OtherPublicModule.class, OkNonPublicModule.class",
- "})",
- "public final class PublicModule {",
- "}");
- JavaFileObject badNonPublicModuleFile =
- JavaFileObjects.forSourceLines(
- "test.BadNonPublicModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "@ProducerModule",
- "final class BadNonPublicModule {",
- " @Produces",
- " int produceInt() {",
- " return 42;",
- " }",
- "}");
- JavaFileObject okNonPublicModuleFile = JavaFileObjects.forSourceLines("test.OkNonPublicModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "@ProducerModule",
- "final class OkNonPublicModule {",
- " @Produces",
- " static String produceString() {",
- " return \"foo\";",
- " }",
- "}");
- JavaFileObject otherPublicModuleFile = JavaFileObjects.forSourceLines("test.OtherPublicModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "",
- "@ProducerModule",
- "public final class OtherPublicModule {",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(
- publicModuleFile,
- badNonPublicModuleFile,
- okNonPublicModuleFile,
- otherPublicModuleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "This module is public, but it includes non-public (or effectively non-public) modules "
- + "(test.BadNonPublicModule) 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.")
- .inFile(publicModuleFile)
- .onLine(8);
- }
-
- @Test public void argumentNamedModuleCompiles() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "@ProducerModule",
- "final class TestModule {",
- " @Produces String produceString(int module) {",
- " return null;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(moduleFile);
- assertThat(compilation).succeeded();
- }
-
- @Test public void singleProducesMethodNoArgsFuture() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "@ProducerModule",
- "final class TestModule {",
- " @Produces ListenableFuture<String> produceString() {",
- " return null;",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProduceStringFactory",
- "package test;",
- "",
- "import com.google.common.util.concurrent.Futures;",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.internal.AbstractProducesMethodProducer;",
- "import dagger.producers.monitoring.ProducerToken;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- "@SuppressWarnings(\"FutureReturnValueIgnored\")",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProduceStringFactory",
- " extends AbstractProducesMethodProducer<Void, String> {",
- " private final TestModule module;",
- "",
- " private TestModule_ProduceStringFactory(",
- " TestModule module,",
- " Provider<Executor> executorProvider,",
- " Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {",
- " super(",
- " productionComponentMonitorProvider,",
- " ProducerToken.create(TestModule_ProduceStringFactory.class),",
- " executorProvider);",
- " this.module = module;",
- " }",
- "",
- " public static TestModule_ProduceStringFactory create(",
- " TestModule module,",
- " Provider<Executor> executorProvider,",
- " Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {",
- " return new TestModule_ProduceStringFactory(",
- " module, executorProvider, productionComponentMonitorProvider);",
- " }",
- "",
- " @Override protected ListenableFuture<Void> collectDependencies() {",
- " return Futures.<Void>immediateFuture(null);",
- " }",
- "",
- " @Override public ListenableFuture<String> callProducesMethod(Void ignoredVoidArg) {",
- " return module.produceString();",
- " }",
- "}");
- assertAbout(javaSource())
- .that(moduleFile)
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(factoryFile);
- }
-
- @Test
- public void singleProducesMethodNoArgsFutureWithProducerName() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "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 TestModule {",
- " @Produces ListenableFuture<String> produceString() {",
- " return Futures.immediateFuture(\"\");",
- " }",
- "}");
- JavaFileObject factoryFile =
- JavaFileObjects.forSourceLines(
- "TestModule_ProduceStringFactory",
- "package test;",
- "",
- "import com.google.common.util.concurrent.Futures;",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.internal.AbstractProducesMethodProducer;",
- "import dagger.producers.monitoring.ProducerToken;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- "@SuppressWarnings(\"FutureReturnValueIgnored\")",
- GENERATED_ANNOTATION,
- "public final class TestModule_ProduceStringFactory",
- " extends AbstractProducesMethodProducer<Void, String> {",
- " private final TestModule module;",
- "",
- " private TestModule_ProduceStringFactory(",
- " TestModule module,",
- " Provider<Executor> executorProvider,",
- " Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {",
- " super(",
- " productionComponentMonitorProvider,",
- " ProducerToken.create(\"test.TestModule#produceString\"),",
- " executorProvider);",
- " this.module = module;",
- " }",
- "",
- " public static TestModule_ProduceStringFactory create(",
- " TestModule module,",
- " Provider<Executor> executorProvider,",
- " Provider<ProductionComponentMonitor> productionComponentMonitorProvider) {",
- " return new TestModule_ProduceStringFactory(",
- " module, executorProvider, productionComponentMonitorProvider);",
- " }",
- "",
- " @Override protected ListenableFuture<Void> collectDependencies() {",
- " return Futures.<Void>immediateFuture(null);",
- " }",
- "",
- " @Override public ListenableFuture<String> callProducesMethod(Void ignoredVoidArg) {",
- " return module.produceString();",
- " }",
- "}");
- assertAbout(javaSource())
- .that(moduleFile)
- .withCompilerOptions("-Adagger.writeProducerNameInToken=ENABLED")
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(factoryFile);
- }
-
- @Test
- public void producesMethodMultipleQualifiersOnMethod() {
- assertThatProductionModuleMethod(
- "@Produces @QualifierA @QualifierB static String produceString() { return null; }")
- .importing(ListenableFuture.class, QualifierA.class, QualifierB.class)
- .hasError("may not use more than one @Qualifier");
- }
-
- @Test
- public void producesMethodMultipleQualifiersOnParameter() {
- assertThatProductionModuleMethod(
- "@Produces static String produceString(@QualifierA @QualifierB Object input) "
- + "{ return null; }")
- .importing(ListenableFuture.class, QualifierA.class, QualifierB.class)
- .hasError("may not use more than one @Qualifier");
- }
-
- @Test
- public void producesMethodWildcardDependency() {
- assertThatProductionModuleMethod(
- "@Produces static String produceString(Provider<? extends Number> numberProvider) "
- + "{ return null; }")
- .importing(ListenableFuture.class, QualifierA.class, QualifierB.class)
- .hasError(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, or Produced<T> "
- + "when T is a wildcard type such as ? extends java.lang.Number");
- }
-
- @Qualifier
- @Retention(RUNTIME)
- public @interface QualifierA {}
-
- @Qualifier
- @Retention(RUNTIME)
- public @interface QualifierB {}
-}
diff --git a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
deleted file mode 100644
index 9a852c7..0000000
--- a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
+++ /dev/null
@@ -1,671 +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;
-
-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.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 ProductionComponentProcessorTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public ProductionComponentProcessorTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test public void componentOnConcreteClass() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent",
- "final class NotAComponent {}");
- Compilation compilation = daggerCompiler().compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void componentOnEnum() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent",
- "enum NotAComponent {",
- " INSTANCE",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void componentOnAnnotation() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent",
- "@interface NotAComponent {}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void nonModuleModule() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = Object.class)",
- "interface NotAComponent {}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("is not annotated with one of @Module, @ProducerModule");
- }
-
- @Test
- public void dependsOnProductionExecutor() {
- JavaFileObject moduleFile =
- 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 Executor executor() {",
- " return MoreExecutors.directExecutor();",
- " }",
- "}");
- JavaFileObject producerModuleFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.Production;",
- "import java.util.concurrent.Executor;",
- "",
- "@ProducerModule",
- "final class SimpleModule {",
- " @Produces String str(@Production Executor executor) {",
- " return \"\";",
- " }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.SimpleComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.concurrent.Executor;",
- "",
- "@ProductionComponent(modules = {ExecutorModule.class, SimpleModule.class})",
- "interface SimpleComponent {",
- " ListenableFuture<String> str();",
- "",
- " @ProductionComponent.Builder",
- " interface Builder {",
- " SimpleComponent build();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(moduleFile, producerModuleFile, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("java.lang.String may not depend on the production executor")
- .inFile(componentFile)
- .onLineContaining("interface SimpleComponent");
-
- compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(producerModuleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .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.
- }
-
- @Test
- public void simpleComponent() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import com.google.common.util.concurrent.MoreExecutors;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.Production;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.concurrent.Executor;",
- "import javax.inject.Inject;",
- "",
- "final class TestClass {",
- " static final class C {",
- " @Inject C() {}",
- " }",
- "",
- " interface A {}",
- " interface B {}",
- "",
- " @Module",
- " static final class BModule {",
- " @Provides B b(C c) {",
- " return null;",
- " }",
- "",
- " @Provides @Production Executor executor() {",
- " return MoreExecutors.directExecutor();",
- " }",
- " }",
- "",
- " @ProducerModule",
- " static final class AModule {",
- " @Produces ListenableFuture<A> a(B b) {",
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(modules = {AModule.class, BModule.class})",
- " interface SimpleComponent {",
- " ListenableFuture<A> a();",
- " }",
- "}");
- JavaFileObject generatedComponent;
- switch (compilerMode) {
- case FAST_INIT_MODE:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestClass_SimpleComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.InstanceFactory;",
- "import dagger.internal.MemoizedSentinel;",
- "import dagger.internal.Preconditions;",
- "import dagger.internal.SetFactory;",
- "import dagger.producers.Producer;",
- "import dagger.producers.internal.CancellationListener;",
- "import dagger.producers.internal.Producers;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestClass_SimpleComponent",
- " implements TestClass.SimpleComponent, CancellationListener {",
- " private final TestClass.BModule bModule;",
- " private volatile Object productionImplementationExecutor =",
- " new MemoizedSentinel();",
- " private volatile Provider<Executor> productionImplementationExecutorProvider;",
- " private volatile Object productionComponentMonitor = new MemoizedSentinel();",
- " private volatile Provider<ProductionComponentMonitor> monitorProvider;",
- " private volatile Provider<TestClass.B> bProvider;",
- " private Producer<TestClass.A> aEntryPoint;",
- " private Provider<TestClass.SimpleComponent> simpleComponentProvider;",
- " private Producer<TestClass.B> bProducer;",
- " private Producer<TestClass.A> aProducer;",
- "",
- " private DaggerTestClass_SimpleComponent(",
- " TestClass.AModule aModuleParam,",
- " TestClass.BModule bModuleParam) {",
- " this.bModule = bModuleParam;",
- " initialize(aModuleParam, bModuleParam);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestClass.SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private Executor getProductionImplementationExecutor() {",
- " Object local = productionImplementationExecutor;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = productionImplementationExecutor;",
- " if (local instanceof MemoizedSentinel) {",
- " local =",
- " TestClass_BModule_ExecutorFactory.executor(bModule);",
- " productionImplementationExecutor =",
- " DoubleCheck.reentrantCheck(",
- " productionImplementationExecutor, local);",
- " }",
- " }",
- " }",
- " return (Executor) local;",
- " }",
- "",
- " private Provider<Executor> getProductionImplementationExecutorProvider() {",
- " Object local = productionImplementationExecutorProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " productionImplementationExecutorProvider = (Provider<Executor>) local;",
- " }",
- " return (Provider<Executor>) local;",
- " }",
- "",
- " private ProductionComponentMonitor getProductionComponentMonitor() {",
- " Object local = productionComponentMonitor;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = productionComponentMonitor;",
- " if (local instanceof MemoizedSentinel) {",
- " local =",
- " TestClass_SimpleComponent_MonitoringModule_MonitorFactory",
- " .monitor(",
- " simpleComponentProvider,",
- " SetFactory.<ProductionComponentMonitor.Factory>empty());",
- " productionComponentMonitor =",
- " DoubleCheck.reentrantCheck(",
- " productionComponentMonitor, local);",
- " }",
- " }",
- " }",
- " return (ProductionComponentMonitor) local;",
- " }",
- "",
- " private Provider<ProductionComponentMonitor>",
- " getProductionComponentMonitorProvider() {",
- " Object local = monitorProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(1);",
- " monitorProvider = (Provider<ProductionComponentMonitor>) local;",
- " }",
- " return (Provider<ProductionComponentMonitor>) local;",
- " }",
- "",
- " private TestClass.B getB() {",
- " return TestClass_BModule_BFactory.b(bModule, new TestClass.C());",
- " }",
- "",
- " private Provider<TestClass.B> getBProvider() {",
- " Object local = bProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(2);",
- " bProvider = (Provider<TestClass.B>) local;",
- " }",
- " return (Provider<TestClass.B>) local;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final TestClass.AModule aModuleParam,",
- " final TestClass.BModule bModuleParam) {",
- " this.simpleComponentProvider =",
- " InstanceFactory.create((TestClass.SimpleComponent) this);",
- " this.bProducer = Producers.producerFromProvider(getBProvider());",
- " this.aProducer =",
- " TestClass_AModule_AFactory.create(",
- " aModuleParam,",
- " getProductionImplementationExecutorProvider(),",
- " getProductionComponentMonitorProvider(),",
- " bProducer);",
- " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
- " }",
- "",
- " @Override",
- " public ListenableFuture<TestClass.A> a() {",
- " return aEntryPoint.get();",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
- " Producers.cancel(aProducer, mayInterruptIfRunning);",
- " Producers.cancel(bProducer, mayInterruptIfRunning);",
- " }",
- "",
- " static final class Builder {",
- " private TestClass.AModule aModule;",
- " private TestClass.BModule bModule;",
- "",
- " private Builder() {}",
- "",
- " public Builder aModule(TestClass.AModule aModule) {",
- " this.aModule = Preconditions.checkNotNull(aModule);",
- " return this;",
- " }",
- "",
- " public Builder bModule(TestClass.BModule bModule) {",
- " this.bModule = Preconditions.checkNotNull(bModule);",
- " return this;",
- " }",
- "",
- " public TestClass.SimpleComponent build() {",
- " if (aModule == null) {",
- " this.aModule = new TestClass.AModule();",
- " }",
- " if (bModule == null) {",
- " this.bModule = new TestClass.BModule();",
- " }",
- " return new DaggerTestClass_SimpleComponent(aModule, bModule);",
- " }",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " private final int id;",
- "",
- " SwitchingProvider(int id) {",
- " this.id = id;",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: return (T) DaggerTestClass_SimpleComponent.this",
- " .getProductionImplementationExecutor();",
- " case 1: return (T)",
- " DaggerTestClass_SimpleComponent.this.getProductionComponentMonitor();",
- " case 2: return (T)",
- " DaggerTestClass_SimpleComponent.this.getB();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
- break;
- default:
- generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestClass_SimpleComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.internal.DoubleCheck;",
- "import dagger.internal.InstanceFactory;",
- "import dagger.internal.Preconditions;",
- "import dagger.internal.SetFactory;",
- "import dagger.producers.Producer;",
- "import dagger.producers.internal.CancellationListener;",
- "import dagger.producers.internal.Producers;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "import java.util.concurrent.Executor;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestClass_SimpleComponent",
- " implements TestClass.SimpleComponent, CancellationListener {",
- " private Producer<TestClass.A> aEntryPoint;",
- " private Provider<Executor> executorProvider;",
- " private Provider<Executor> productionImplementationExecutorProvider;",
- " private Provider<TestClass.SimpleComponent> simpleComponentProvider;",
- " private Provider<ProductionComponentMonitor> monitorProvider;",
- " private Provider<TestClass.B> bProvider;",
- " private Producer<TestClass.B> bProducer;",
- " private Producer<TestClass.A> aProducer;",
- "",
- " private DaggerTestClass_SimpleComponent(",
- " TestClass.AModule aModuleParam,",
- " TestClass.BModule bModuleParam) {",
- " initialize(aModuleParam, bModuleParam);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestClass.SimpleComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(",
- " final TestClass.AModule aModuleParam,",
- " final TestClass.BModule bModuleParam) {",
- " this.executorProvider =",
- " TestClass_BModule_ExecutorFactory.create(bModuleParam);",
- " this.productionImplementationExecutorProvider =",
- " DoubleCheck.provider((Provider) executorProvider);",
- " this.simpleComponentProvider = ",
- " InstanceFactory.create((TestClass.SimpleComponent) this);",
- " this.monitorProvider =",
- " DoubleCheck.provider(",
- " TestClass_SimpleComponent_MonitoringModule_MonitorFactory.create(",
- " simpleComponentProvider,",
- " SetFactory.<ProductionComponentMonitor.Factory>empty()));",
- " this.bProvider = TestClass_BModule_BFactory.create(",
- " bModuleParam, TestClass_C_Factory.create());",
- " this.bProducer = Producers.producerFromProvider(bProvider);",
- " this.aProducer = TestClass_AModule_AFactory.create(",
- " aModuleParam,",
- " productionImplementationExecutorProvider,",
- " monitorProvider,",
- " bProducer);",
- " this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
- " }",
- "",
- " @Override",
- " public ListenableFuture<TestClass.A> a() {",
- " return aEntryPoint.get();",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
- " Producers.cancel(aProducer, mayInterruptIfRunning);",
- " Producers.cancel(bProducer, mayInterruptIfRunning);",
- " }",
- "",
- " static final class Builder {",
- " private TestClass.AModule aModule;",
- " private TestClass.BModule bModule;",
- "",
- " private Builder() {}",
- "",
- " public Builder aModule(TestClass.AModule aModule) {",
- " this.aModule = Preconditions.checkNotNull(aModule);",
- " return this;",
- " }",
- "",
- " public Builder bModule(TestClass.BModule bModule) {",
- " this.bModule = Preconditions.checkNotNull(bModule);",
- " return this;",
- " }",
- "",
- " public TestClass.SimpleComponent build() {",
- " if (aModule == null) {",
- " this.aModule = new TestClass.AModule();",
- " }",
- " if (bModule == null) {",
- " this.bModule = new TestClass.BModule();",
- " }",
- " return new DaggerTestClass_SimpleComponent(aModule, bModule);",
- " }",
- " }",
- "}");
- }
- assertAbout(javaSource())
- .that(component)
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(generatedComponent);
- }
-
- @Test public void nullableProducersAreNotErrors() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import com.google.common.util.concurrent.MoreExecutors;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.Production;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.concurrent.Executor;",
- "import javax.annotation.Nullable;",
- "import javax.inject.Inject;",
- "",
- "final class TestClass {",
- " interface A {}",
- " interface B {}",
- " interface C {}",
- "",
- " @Module",
- " static final class CModule {",
- " @Provides @Nullable C c() {",
- " return null;",
- " }",
- "",
- " @Provides @Production Executor executor() {",
- " return MoreExecutors.directExecutor();",
- " }",
- " }",
- "",
- " @ProducerModule",
- " static final class ABModule {",
- " @Produces @Nullable B b(@Nullable C c) {",
- " return null;",
- " }",
-
- " @Produces @Nullable ListenableFuture<A> a(B b) {", // NOTE: B not injected as nullable
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(modules = {ABModule.class, CModule.class})",
- " interface SimpleComponent {",
- " ListenableFuture<A> a();",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining("@Nullable on @Produces methods does not do anything")
- .inFile(component)
- .onLine(33);
- assertThat(compilation)
- .hadWarningContaining("@Nullable on @Produces methods does not do anything")
- .inFile(component)
- .onLine(36);
- }
-
- @Test
- public void productionScope_injectConstructor() {
- JavaFileObject productionScoped =
- JavaFileObjects.forSourceLines(
- "test.ProductionScoped",
- "package test;",
- "",
- "import dagger.producers.ProductionScope;",
- "import javax.inject.Inject;",
- "",
- "@ProductionScope",
- "class ProductionScoped {",
- " @Inject ProductionScoped() {}",
- "}");
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.producers.ProductionSubcomponent;",
- "",
- "@ProductionSubcomponent",
- "interface Child {",
- " ProductionScoped productionScoped();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(productionScoped, parent, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(
- new JavaFileBuilder(compilerMode, "test.DaggerRoot")
- .addLines(
- "package test;",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent, CancellationListener {",
- " private final class ChildImpl implements Child, CancellationListener {",
- " @Override",
- " public ProductionScoped productionScoped() {")
- .addLinesIn(
- CompilerMode.DEFAULT_MODE, //
- " return DaggerParent.this.productionScopedProvider.get();")
- .addLinesIn(
- CompilerMode.FAST_INIT_MODE, //
- " return DaggerParent.this.getProductionScoped();")
- .addLines(
- " }", //
- " }", //
- "}")
- .build());
- }
-}
diff --git a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
deleted file mode 100644
index 8453e03..0000000
--- a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
+++ /dev/null
@@ -1,495 +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;
-
-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;
-
-/** Producer-specific validation tests. */
-@RunWith(JUnit4.class)
-public class ProductionGraphValidationTest {
- private static final JavaFileObject EXECUTOR_MODULE =
- 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",
- "class ExecutorModule {",
- " @Provides @Production Executor executor() {",
- " return MoreExecutors.directExecutor();",
- " }",
- "}");
-
- @Test public void componentWithUnprovidedInput() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.MyComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = {ExecutorModule.class, FooModule.class})",
- "interface MyComponent {",
- " ListenableFuture<Foo> getFoo();",
- "}");
- JavaFileObject module = JavaFileObjects.forSourceLines("test.FooModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "",
- "class Foo {}",
- "class Bar {}",
- "",
- "@ProducerModule",
- "class FooModule {",
- " @Produces Foo foo(Bar bar) {",
- " return null;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, module, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.Bar cannot be provided without an @Inject constructor or an @Provides- or "
- + "@Produces-annotated method.")
- .inFile(component)
- .onLineContaining("interface MyComponent");
- }
-
- @Test public void componentProductionWithNoDependencyChain() {
- JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " @ProductionComponent(modules = ExecutorModule.class)",
- " interface AComponent {",
- " ListenableFuture<A> getA();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.TestClass.A cannot be provided without an @Provides- or @Produces-annotated "
- + "method.")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test public void provisionDependsOnProduction() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.Provides;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.ProductionComponent;",
- "",
- "final class TestClass {",
- " interface A {}",
- " interface B {}",
- "",
- " @ProducerModule(includes = BModule.class)",
- " final class AModule {",
- " @Provides A a(B b) {",
- " return null;",
- " }",
- " }",
- "",
- " @ProducerModule",
- " final class BModule {",
- " @Produces ListenableFuture<B> b() {",
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(modules = {ExecutorModule.class, AModule.class})",
- " interface AComponent {",
- " ListenableFuture<A> getA();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production.")
- .inFile(component)
- .onLineContaining("interface AComponent");
-
- compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production.")
- .inFile(component)
- .onLineContaining("class AModule");
- }
-
- @Test public void provisionEntryPointDependsOnProduction() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.ProductionComponent;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " @ProducerModule",
- " static final class AModule {",
- " @Produces ListenableFuture<A> a() {",
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(modules = {ExecutorModule.class, AModule.class})",
- " interface AComponent {",
- " A getA();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.TestClass.A is a provision entry-point, which cannot depend on a production.")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test
- public void providingMultibindingWithProductions() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "final class TestClass {",
- " interface A {}",
- " interface B {}",
- "",
- " @Module",
- " static final class AModule {",
- " @Provides static A a(Map<String, Provider<Object>> map) {",
- " return null;",
- " }",
- "",
- " @Provides @IntoMap @StringKey(\"a\") static Object aEntry() {",
- " return \"a\";",
- " }",
- " }",
- "",
- " @ProducerModule",
- " static final class BModule {",
- " @Produces static B b(A a) {",
- " return null;",
- " }",
- "",
- " @Produces @IntoMap @StringKey(\"b\") static Object bEntry() {",
- " return \"b\";",
- " }",
- " }",
- "",
- " @ProductionComponent(",
- " modules = {ExecutorModule.class, AModule.class, BModule.class})",
- " interface AComponent {",
- " ListenableFuture<B> b();",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production")
- .inFile(component)
- .onLineContaining("interface AComponent");
- }
-
- @Test
- public void monitoringDependsOnUnboundType() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.ProductionComponent;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " @Module",
- " final class MonitoringModule {",
- " @Provides @IntoSet",
- " ProductionComponentMonitor.Factory monitorFactory(A unbound) {",
- " return null;",
- " }",
- " }",
- "",
- " @ProducerModule",
- " final class StringModule {",
- " @Produces ListenableFuture<String> str() {",
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(",
- " modules = {ExecutorModule.class, MonitoringModule.class, StringModule.class}",
- " )",
- " interface StringComponent {",
- " ListenableFuture<String> getString();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.TestClass.A cannot be provided without an @Provides-annotated method.")
- .inFile(component)
- .onLineContaining("interface StringComponent");
- }
-
- @Test
- public void monitoringDependsOnProduction() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestClass",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.producers.ProductionComponent;",
- "import dagger.producers.monitoring.ProductionComponentMonitor;",
- "",
- "final class TestClass {",
- " interface A {}",
- "",
- " @Module",
- " final class MonitoringModule {",
- " @Provides @IntoSet ProductionComponentMonitor.Factory monitorFactory(A a) {",
- " return null;",
- " }",
- " }",
- "",
- " @ProducerModule",
- " final class StringModule {",
- " @Produces A a() {",
- " return null;",
- " }",
- "",
- " @Produces ListenableFuture<String> str() {",
- " return null;",
- " }",
- " }",
- "",
- " @ProductionComponent(",
- " modules = {ExecutorModule.class, MonitoringModule.class, StringModule.class}",
- " )",
- " interface StringComponent {",
- " ListenableFuture<String> getString();",
- " }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "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");
- }
-
- @Test
- public void cycleNotBrokenByMap() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = {ExecutorModule.class, TestModule.class})",
- "interface TestComponent {",
- " ListenableFuture<String> string();",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "import java.util.Map;",
- "",
- "@ProducerModule",
- "final class TestModule {",
- " @Produces static String string(Map<String, String> map) {",
- " return \"string\";",
- " }",
- "",
- " @Produces @IntoMap @StringKey(\"key\")",
- " static String entry(String string) {",
- " return string;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component, module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cycle")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void cycleNotBrokenByProducerMap() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(modules = {ExecutorModule.class, TestModule.class})",
- "interface TestComponent {",
- " ListenableFuture<String> string();",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.producers.Producer;",
- "import dagger.producers.ProducerModule;",
- "import dagger.producers.Produces;",
- "import dagger.multibindings.StringKey;",
- "import dagger.multibindings.IntoMap;",
- "import java.util.Map;",
- "",
- "@ProducerModule",
- "final class TestModule {",
- " @Produces static String string(Map<String, Producer<String>> map) {",
- " return \"string\";",
- " }",
- "",
- " @Produces @IntoMap @StringKey(\"key\")",
- " static String entry(String string) {",
- " return string;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component, module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("cycle")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void componentWithBadModule() {
- JavaFileObject badModule =
- JavaFileObjects.forSourceLines(
- "test.BadModule",
- "package test;",
- "",
- "import dagger.BindsOptionalOf;",
- "import dagger.multibindings.Multibinds;",
- "import dagger.Module;",
- "import java.util.Set;",
- "",
- "@Module",
- "abstract class BadModule {",
- " @Multibinds",
- " @BindsOptionalOf",
- " abstract Set<String> strings();",
- "}");
- JavaFileObject badComponent =
- JavaFileObjects.forSourceLines(
- "test.BadComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Optional;",
- "import java.util.Set;",
- "",
- "@Component(modules = BadModule.class)",
- "interface BadComponent {",
- " Set<String> strings();",
- " Optional<Set<String>> optionalStrings();",
- "}");
- Compilation compilation = daggerCompiler().compile(badModule, badComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("test.BadModule has errors")
- .inFile(badComponent)
- .onLine(7);
- }
-}
diff --git a/javatests/dagger/internal/codegen/RepeatedModuleValidationTest.java b/javatests/dagger/internal/codegen/RepeatedModuleValidationTest.java
deleted file mode 100644
index 60a9bd5..0000000
--- a/javatests/dagger/internal/codegen/RepeatedModuleValidationTest.java
+++ /dev/null
@@ -1,135 +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;
-
-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 class RepeatedModuleValidationTest {
- private static final JavaFileObject MODULE_FILE =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class TestModule {}");
-
- @Test
- public void moduleRepeatedInSubcomponentFactoryMethod() {
- JavaFileObject subcomponentFile =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "interface TestSubcomponent {",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " TestSubcomponent newTestSubcomponent(TestModule module);",
- "}");
- Compilation compilation =
- daggerCompiler().compile(MODULE_FILE, subcomponentFile, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("TestModule is present in test.TestComponent.")
- .inFile(componentFile)
- .onLine(7)
- .atColumn(51);
- }
-
- @Test
- public void moduleRepeatedInSubcomponentBuilderMethod() {
- JavaFileObject subcomponentFile =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "interface TestSubcomponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Builder testModule(TestModule testModule);",
- " TestSubcomponent build();",
- " }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " TestSubcomponent.Builder newTestSubcomponentBuilder();",
- "}");
- Compilation compilation =
- daggerCompiler().compile(MODULE_FILE, subcomponentFile, componentFile);
- assertThat(compilation).succeeded();
- // TODO(gak): assert about the warning when we have that ability
- }
-
- @Test
- public void moduleRepeatedButNotPassed() {
- JavaFileObject subcomponentFile =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "interface TestSubcomponent {",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " TestSubcomponent newTestSubcomponent();",
- "}");
- Compilation compilation =
- daggerCompiler().compile(MODULE_FILE, subcomponentFile, componentFile);
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/internal/codegen/ScopingValidationTest.java b/javatests/dagger/internal/codegen/ScopingValidationTest.java
deleted file mode 100644
index 9efcc2a..0000000
--- a/javatests/dagger/internal/codegen/ScopingValidationTest.java
+++ /dev/null
@@ -1,700 +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;
-
-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;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ScopingValidationTest {
- @Test
- public void componentWithoutScopeIncludesScopedBindings_Fail() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.MyComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Component(modules = ScopedModule.class)",
- "interface MyComponent {",
- " ScopedType string();",
- "}");
- JavaFileObject typeFile =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "class ScopedType {",
- " @Inject ScopedType(String s, long l, float f) {}",
- "}");
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.ScopedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "class ScopedModule {",
- " @Provides @Singleton String string() { return \"a string\"; }",
- " @Provides long integer() { return 0L; }",
- " @Provides float floatingPoint() { return 0.0f; }",
- "}");
-
- Compilation compilation = daggerCompiler().compile(componentFile, typeFile, moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.MyComponent (unscoped) may not reference scoped bindings:",
- " @Singleton class test.ScopedType",
- " @Provides @Singleton String test.ScopedModule.string()"));
- }
-
- @Test // b/79859714
- public void bindsWithChildScope_inParentModule_notAllowed() {
- JavaFileObject childScope =
- JavaFileObjects.forSourceLines(
- "test.ChildScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface ChildScope {}");
-
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "", //
- "interface Foo {}");
-
- JavaFileObject fooImpl =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FooImpl implements Foo {",
- " @Inject FooImpl() {}",
- "}");
-
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Binds @ChildScope Foo bind(FooImpl fooImpl);",
- "}");
-
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
-
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@ChildScope",
- "@Subcomponent",
- "interface Child {",
- " Foo foo();",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(childScope, foo, fooImpl, parentModule, parent, child);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.Parent scoped with @Singleton may not reference bindings with different "
- + "scopes:",
- " @Binds @test.ChildScope test.Foo test.ParentModule.bind(test.FooImpl)"));
- }
-
- @Test
- public void componentWithScopeIncludesIncompatiblyScopedBindings_Fail() {
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.MyComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = ScopedModule.class)",
- "interface MyComponent {",
- " ScopedType string();",
- "}");
- JavaFileObject scopeFile =
- JavaFileObjects.forSourceLines(
- "test.PerTest",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface PerTest {}");
- JavaFileObject scopeWithAttribute =
- JavaFileObjects.forSourceLines(
- "test.Per",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface Per {",
- " Class<?> value();",
- "}");
- JavaFileObject typeFile =
- JavaFileObjects.forSourceLines(
- "test.ScopedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@PerTest", // incompatible scope
- "class ScopedType {",
- " @Inject ScopedType(String s, long l, float f, boolean b) {}",
- "}");
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.ScopedModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "class ScopedModule {",
- " @Provides @PerTest String string() { return \"a string\"; }", // incompatible scope
- " @Provides long integer() { return 0L; }", // unscoped - valid
- " @Provides @Singleton float floatingPoint() { return 0.0f; }", // same scope - valid
- " @Provides @Per(MyComponent.class) boolean bool() { return false; }", // incompatible
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .compile(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.MyComponent scoped with @Singleton "
- + "may not reference bindings with different scopes:",
- " @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 =
- 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(
- "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");
- }
-
- @Test
- public void fullBindingGraphValidationDoesNotReportForOneScope() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- "-Adagger.fullBindingGraphValidation=ERROR",
- "-Adagger.moduleHasDifferentScopesValidation=ERROR")
- .compile(
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides @Singleton static Object object() { return \"object\"; }",
- " @Provides @Singleton static String string() { return \"string\"; }",
- " @Provides static int integer() { return 4; }",
- "}"));
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void fullBindingGraphValidationDoesNotReportInjectBindings() {
- Compilation compilation =
- daggerCompiler()
- .withOptions(
- "-Adagger.fullBindingGraphValidation=ERROR",
- "-Adagger.moduleHasDifferentScopesValidation=ERROR")
- .compile(
- JavaFileObjects.forSourceLines(
- "test.UsedInRootRedScoped",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@RedScope",
- "final class UsedInRootRedScoped {",
- " @Inject UsedInRootRedScoped() {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.UsedInRootBlueScoped",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@BlueScope",
- "final class UsedInRootBlueScoped {",
- " @Inject UsedInRootBlueScoped() {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.RedScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface RedScope {}"),
- JavaFileObjects.forSourceLines(
- "test.BlueScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope",
- "@interface BlueScope {}"),
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module(subcomponents = Child.class)",
- "interface TestModule {",
- " @Provides @Singleton",
- " static Object object(",
- " UsedInRootRedScoped usedInRootRedScoped,",
- " UsedInRootBlueScoped usedInRootBlueScoped) {",
- " return \"object\";",
- " }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child {",
- " UsedInChildRedScoped usedInChildRedScoped();",
- " UsedInChildBlueScoped usedInChildBlueScoped();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child child();",
- " }",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.UsedInChildRedScoped",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@RedScope",
- "final class UsedInChildRedScoped {",
- " @Inject UsedInChildRedScoped() {}",
- "}"),
- JavaFileObjects.forSourceLines(
- "test.UsedInChildBlueScoped",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "@BlueScope",
- "final class UsedInChildBlueScoped {",
- " @Inject UsedInChildBlueScoped() {}",
- "}"));
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- 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",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class SimpleType {",
- " @Inject SimpleType() {}",
- " static class A { @Inject A() {} }",
- " static class B { @Inject B() {} }",
- "}");
- JavaFileObject simpleScope =
- JavaFileObjects.forSourceLines(
- "test.SimpleScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface SimpleScope {}");
- JavaFileObject singletonScopedA =
- JavaFileObjects.forSourceLines(
- "test.SingletonComponentA",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface SingletonComponentA {",
- " SimpleType.A type();",
- "}");
- JavaFileObject singletonScopedB =
- JavaFileObjects.forSourceLines(
- "test.SingletonComponentB",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface SingletonComponentB {",
- " SimpleType.B type();",
- "}");
- JavaFileObject scopeless =
- JavaFileObjects.forSourceLines(
- "test.ScopelessComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ScopelessComponent {",
- " SimpleType type();",
- "}");
- JavaFileObject simpleScoped =
- JavaFileObjects.forSourceLines(
- "test.SimpleScopedComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@SimpleScope",
- "@Component(dependencies = {SingletonComponentA.class, SingletonComponentB.class})",
- "interface SimpleScopedComponent {",
- " SimpleType.A type();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .compile(
- type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless);
- 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
- public void componentWithoutScopeCannotDependOnScopedComponent() {
- JavaFileObject type =
- JavaFileObjects.forSourceLines(
- "test.SimpleType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class SimpleType {",
- " @Inject SimpleType() {}",
- "}");
- JavaFileObject scopedComponent =
- JavaFileObjects.forSourceLines(
- "test.ScopedComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface ScopedComponent {",
- " SimpleType type();",
- "}");
- JavaFileObject unscopedComponent =
- JavaFileObjects.forSourceLines(
- "test.UnscopedComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Component(dependencies = ScopedComponent.class)",
- "interface UnscopedComponent {",
- " SimpleType type();",
- "}");
-
- Compilation compilation = daggerCompiler().compile(type, scopedComponent, unscopedComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.UnscopedComponent (unscoped) cannot depend on scoped components:",
- " @Singleton test.ScopedComponent"));
- }
-
- @Test
- public void componentWithSingletonScopeMayNotDependOnOtherScope() {
- // Singleton must be the widest lifetime of present scopes.
- 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 simpleScoped =
- JavaFileObjects.forSourceLines(
- "test.SimpleScopedComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@SimpleScope",
- "@Component",
- "interface SimpleScopedComponent {",
- " SimpleType type();",
- "}");
- JavaFileObject singletonScoped =
- JavaFileObjects.forSourceLines(
- "test.SingletonComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(dependencies = SimpleScopedComponent.class)",
- "interface SingletonComponent {",
- " SimpleType type();",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(type, simpleScope, simpleScoped, singletonScoped);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "This @Singleton component cannot depend on scoped components:",
- " @test.SimpleScope test.SimpleScopedComponent"));
- }
-
- @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
- // scopes on components such that they cycle.
- 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 mediumLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentMedium",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeB",
- "@Component(dependencies = ComponentLong.class)",
- "interface ComponentMedium {",
- " SimpleType type();",
- "}");
- JavaFileObject shortLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentShort",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeA",
- "@Component(dependencies = ComponentMedium.class)",
- "interface ComponentShort {",
- " SimpleType type();",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(type, scopeA, scopeB, longLifetime, mediumLifetime, 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.ComponentMedium",
- " @test.ScopeA test.ComponentShort"));
- }
-
- @Test
- public void reusableNotAllowedOnComponent() {
- JavaFileObject someComponent =
- JavaFileObjects.forSourceLines(
- "test.SomeComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Reusable;",
- "",
- "@Reusable",
- "@Component",
- "interface SomeComponent {}");
- Compilation compilation = daggerCompiler().compile(someComponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Reusable cannot be applied to components or subcomponents")
- .inFile(someComponent)
- .onLine(6);
- }
-
- @Test
- public void reusableNotAllowedOnSubcomponent() {
- JavaFileObject someSubcomponent =
- JavaFileObjects.forSourceLines(
- "test.SomeComponent",
- "package test;",
- "",
- "import dagger.Reusable;",
- "import dagger.Subcomponent;",
- "",
- "@Reusable",
- "@Subcomponent",
- "interface SomeSubcomponent {}");
- Compilation compilation = daggerCompiler().compile(someSubcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@Reusable cannot be applied to components or subcomponents")
- .inFile(someSubcomponent)
- .onLine(6);
- }
-}
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
deleted file mode 100644
index 3fb0e9c..0000000
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
+++ /dev/null
@@ -1,322 +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;
-
-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.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 SetBindingRequestFulfillmentTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public SetBindingRequestFulfillmentTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void setBindings() {
- JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "abstract class EmptySetModule {",
- " @Multibinds abstract Set<Object> objects();",
- "",
- " @Provides @ElementsIntoSet",
- " static Set<String> emptySet() { ",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Module",
- "final class SetModule {",
- " @Provides @IntoSet static String string() { return \"\"; }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {EmptySetModule.class, SetModule.class})",
- "interface TestComponent {",
- " Set<String> strings();",
- " Set<Object> objects();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.SetBuilder;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Set<String> strings() {",
- " return SetBuilder.<String>newSetBuilder(2)",
- " .addAll(EmptySetModule_EmptySetFactory.emptySet())",
- " .add(SetModule_StringFactory.string())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Set<Object> objects() {",
- " return Collections.<Object>emptySet();",
- " }",
- "}");
- Compilation compilation =
- daggerCompilerWithoutGuava().compile(emptySetModuleFile, setModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "class Inaccessible {}");
- JavaFileObject inaccessible2 =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible2",
- "package other;",
- "",
- "class Inaccessible2 {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Set;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Set<Inaccessible> set1, Set<Inaccessible2> set2) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Set<Inaccessible> objects();",
- "",
- " @Provides @ElementsIntoSet",
- " static Set<Inaccessible2> emptySet() { ",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.SetBuilder;",
- "import other.TestModule_EmptySetFactory;",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Set getSetOfInaccessible2() {",
- " return SetBuilder.newSetBuilder(1)",
- " .addAll(TestModule_EmptySetFactory.emptySet())",
- " .build();",
- " }",
- "",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newInstance(",
- " (Set) Collections.emptySet(),",
- " (Set) getSetOfInaccessible2());",
- " }",
- "}");
- Compilation compilation =
- daggerCompilerWithoutGuava()
- .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoSet static Object parentObject() {",
- " return \"parent object\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Set;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Set<Object> objectSet();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- "import java.util.Collections;",
- "import java.util.Set;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private DaggerParent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static Parent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public Child child() {",
- " return new ChildImpl();",
- " }",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " @Deprecated",
- " public Builder parentModule(ParentModule parentModule) {",
- " Preconditions.checkNotNull(parentModule);",
- " return this;",
- " }",
- "",
- " public Parent build() {",
- " return new DaggerParent();",
- " }",
- " }",
- "",
- " private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
- "",
- " @Override",
- " public Set<Object> objectSet() {",
- " return Collections.<Object>singleton(",
- " ParentModule_ParentObjectFactory.parentObject());",
- " }",
- " }",
- "}");
-
- Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- private Compiler daggerCompilerWithoutGuava() {
- 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
deleted file mode 100644
index 7a47393..0000000
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
+++ /dev/null
@@ -1,380 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-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;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 SetBindingRequestFulfillmentWithGuavaTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public SetBindingRequestFulfillmentWithGuavaTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void setBindings() {
- JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "abstract class EmptySetModule {",
- " @Multibinds abstract Set<Object> objects();",
- "",
- " @Provides @ElementsIntoSet",
- " static Set<String> emptySet() { ",
- " return Collections.emptySet();",
- " }",
- " @Provides @ElementsIntoSet",
- " static Set<Integer> onlyContributionIsElementsIntoSet() { ",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Module",
- "final class SetModule {",
- " @Provides @IntoSet static String string() { return \"\"; }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = {EmptySetModule.class, SetModule.class})",
- "interface TestComponent {",
- " Set<String> strings();",
- " Set<Object> objects();",
- " Set<Integer> onlyContributionIsElementsIntoSet();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableSet;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Set<String> strings() {",
- " return ImmutableSet.<String>builderWithExpectedSize(2)",
- " .addAll(EmptySetModule_EmptySetFactory.emptySet())",
- " .add(SetModule_StringFactory.string())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Set<Object> objects() {",
- " return ImmutableSet.<Object>of();",
- " }",
- "",
- " @Override",
- " public Set<Integer> onlyContributionIsElementsIntoSet() {",
- " return ImmutableSet.<Integer>copyOf(",
- " EmptySetModule_OnlyContributionIsElementsIntoSetFactory",
- " .onlyContributionIsElementsIntoSet());",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(emptySetModuleFile, setModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "class Inaccessible {}");
- JavaFileObject inaccessible2 =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible2",
- "package other;",
- "",
- "class Inaccessible2 {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Set;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Set<Inaccessible> set1, Set<Inaccessible2> set2) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Set<Inaccessible> objects();",
- "",
- " @Provides @ElementsIntoSet",
- " static Set<Inaccessible2> emptySet() { ",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Set;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableSet;",
- "import other.TestModule_EmptySetFactory;",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Set getSetOfInaccessible2() {",
- " return ImmutableSet.copyOf(TestModule_EmptySetFactory.emptySet());",
- " }",
- "",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newInstance(",
- " (Set) ImmutableSet.of(),",
- " (Set) getSetOfInaccessible2());",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoSet;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoSet static Object parentObject() {",
- " return \"parent object\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Set;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Set<Object> objectSet();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableSet;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParent implements Parent {",
- " private final class ChildImpl implements Child {",
- " @Override",
- " public Set<Object> objectSet() {",
- " return ImmutableSet.<Object>of(",
- " ParentModule_ParentObjectFactory.parentObject());",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void productionComponents() {
- JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "abstract class EmptySetModule {",
- " @Provides @ElementsIntoSet",
- " static Set<String> emptySet() { ",
- " return Collections.emptySet();",
- " }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.Set;",
- "",
- "@ProductionComponent(modules = EmptySetModule.class)",
- "interface TestComponent {",
- " ListenableFuture<Set<String>> strings();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableSet;",
- "import com.google.common.util.concurrent.Futures;",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.internal.CancellationListener;",
- "import java.util.Set;",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent, "
- + "CancellationListener {",
- " private DaggerTestComponent() {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " private Set<String> getSetOfString() {",
- " return ImmutableSet.<String>copyOf(",
- " EmptySetModule_EmptySetFactory.emptySet());",
- " }",
- "",
- " @Override",
- " public ListenableFuture<Set<String>> strings() {",
- " return Futures.immediateFuture(getSetOfString());",
- " }",
- "",
- " @Override",
- " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {}",
- "",
- " static final class Builder {",
- " private Builder() {}",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent();",
- " }",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(emptySetModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/SourceFilesTest.java b/javatests/dagger/internal/codegen/SourceFilesTest.java
deleted file mode 100644
index c7fe998..0000000
--- a/javatests/dagger/internal/codegen/SourceFilesTest.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;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.SourceFiles.simpleVariableName;
-
-import com.google.testing.compile.CompilationRule;
-import java.util.List;
-import javax.lang.model.element.TypeElement;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link SourceFiles}. */
-@RunWith(JUnit4.class)
-public final class SourceFilesTest {
- @Rule public CompilationRule compilation = new CompilationRule();
-
- private TypeElement typeElementFor(Class<?> clazz) {
- return compilation.getElements().getTypeElement(clazz.getCanonicalName());
- }
-
- private static final class Int {}
-
- @Test
- public void testSimpleVariableName_typeCollisions() {
- // a handful of boxed types
- assertThat(simpleVariableName(typeElementFor(Long.class))).isEqualTo("l");
- assertThat(simpleVariableName(typeElementFor(Double.class))).isEqualTo("d");
- // not a boxed type type, but a custom type might collide
- assertThat(simpleVariableName(typeElementFor(Int.class))).isEqualTo("i");
- // void is the weird pseudo-boxed type
- assertThat(simpleVariableName(typeElementFor(Void.class))).isEqualTo("v");
- // reflective types
- assertThat(simpleVariableName(typeElementFor(Class.class))).isEqualTo("clazz");
- assertThat(simpleVariableName(typeElementFor(Package.class))).isEqualTo("pkg");
- }
-
- private static final class For {}
-
- private static final class Goto {}
-
- @Test
- public void testSimpleVariableName_randomKeywords() {
- assertThat(simpleVariableName(typeElementFor(For.class))).isEqualTo("for_");
- assertThat(simpleVariableName(typeElementFor(Goto.class))).isEqualTo("goto_");
- }
-
- @Test
- public void testSimpleVariableName() {
- assertThat(simpleVariableName(typeElementFor(Object.class))).isEqualTo("object");
- assertThat(simpleVariableName(typeElementFor(List.class))).isEqualTo("list");
- }
-}
diff --git a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
deleted file mode 100644
index 5dab4c4..0000000
--- a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
+++ /dev/null
@@ -1,192 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-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 javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link dagger.Subcomponent.Builder} validation. */
-@RunWith(JUnit4.class)
-public class SubcomponentBuilderValidationTest {
-
- private static final ErrorMessages.ComponentCreatorMessages MSGS =
- creatorMessagesFor(SUBCOMPONENT_BUILDER);
-
- @Test
- public void testMoreThanOneArgFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " Builder set(String s, Integer i);",
- " Builder set(Number n, Double d);",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
- .inFile(childComponentFile)
- .onLine(10);
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
- .inFile(childComponentFile)
- .onLine(11);
- }
-
- @Test
- public void testInheritedMoreThanOneArgFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " interface Parent {",
- " ChildComponent build();",
- " Builder set1(String s, Integer i);",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- MSGS.inheritedSetterMethodsMustTakeOneArg(),
- "set1(java.lang.String,java.lang.Integer)"))
- .inFile(childComponentFile)
- .onLine(13);
- }
-
- @Test
- public void testSetterReturningNonVoidOrBuilderFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " String set(Integer i);",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder())
- .inFile(childComponentFile)
- .onLine(10);
- }
-
- @Test
- public void testInheritedSetterReturningNonVoidOrBuilderFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " interface Parent {",
- " ChildComponent build();",
- " String set(Integer i);",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- MSGS.inheritedSetterMethodsMustReturnVoidOrBuilder(), "set(java.lang.Integer)"))
- .inFile(childComponentFile)
- .onLine(13);
- }
-
- @Test
- public void testGenericsOnSetterMethodFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " <T> Builder set(T t);",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
- .inFile(childComponentFile)
- .onLine(10);
- }
-
- @Test
- public void testGenericsOnInheritedSetterMethodFails() {
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " interface Parent {",
- " ChildComponent build();",
- " <T> Builder set(T t);",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = daggerCompiler().compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)"))
- .inFile(childComponentFile)
- .onLine(13);
- }
-}
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
deleted file mode 100644
index de0067f..0000000
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.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;
-
-import static com.google.common.collect.Sets.cartesianProduct;
-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.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 com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.testing.compile.Compilation;
-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;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class SubcomponentCreatorRequestFulfillmentTest extends ComponentCreatorTestHelper {
- @Parameters(name = "compilerMode={0}, creatorKind={1}")
- public static Collection<Object[]> parameters() {
- Set<List<Object>> params =
- cartesianProduct(
- immutableEnumSet(DEFAULT_MODE, FAST_INIT_MODE),
- immutableEnumSet(SUBCOMPONENT_FACTORY, SUBCOMPONENT_BUILDER));
- return ImmutableList.copyOf(Iterables.transform(params, Collection::toArray));
- }
-
- public SubcomponentCreatorRequestFulfillmentTest(
- CompilerMode compilerMode, ComponentCreatorAnnotation componentCreatorAnnotation) {
- super(compilerMode, componentCreatorAnnotation);
- }
-
- @Test
- public void testInlinedSubcomponentCreators_componentMethod() {
- JavaFileObject subcomponent =
- preprocessedJavaFile(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- "}");
- JavaFileObject usesSubcomponent =
- preprocessedJavaFile(
- "test.UsesSubcomponent",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class UsesSubcomponent {",
- " @Inject UsesSubcomponent(Sub.Builder subBuilder) {}",
- "}");
- JavaFileObject component =
- preprocessedJavaFile(
- "test.C",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface C {",
- " Sub.Builder sBuilder();",
- " UsesSubcomponent usesSubcomponent();",
- "}");
-
- JavaFileObject generatedComponent =
- preprocessedJavaFile(
- "test.DaggerC",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerC implements C {",
- " @Override",
- " public Sub.Builder sBuilder() {",
- " return new SubBuilder();",
- " }",
- "",
- " @Override",
- " public UsesSubcomponent usesSubcomponent() {",
- " return new UsesSubcomponent(new SubBuilder());",
- " }",
- "",
- " private final class SubBuilder implements Sub.Builder {",
- " @Override",
- " public Sub build() {",
- " return new SubImpl();",
- " }",
- " }",
- "",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- " }",
- "}");
-
- Compilation compilation = compile(subcomponent, usesSubcomponent, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerC")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
deleted file mode 100644
index b5753d4..0000000
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
+++ /dev/null
@@ -1,987 +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;
-
-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 com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/** Tests for {@link dagger.Subcomponent.Builder} validation. */
-@RunWith(Parameterized.class)
-public class SubcomponentCreatorValidationTest extends ComponentCreatorTestHelper {
- @Parameters(name = "creatorKind={0}")
- public static Collection<Object[]> parameters() {
- return ImmutableList.copyOf(new Object[][] {{SUBCOMPONENT_BUILDER}, {SUBCOMPONENT_FACTORY}});
- }
-
- public SubcomponentCreatorValidationTest(ComponentCreatorAnnotation componentCreatorAnnotation) {
- super(DEFAULT_MODE, componentCreatorAnnotation);
- }
-
- @Test
- public void testRefSubcomponentAndSubCreatorFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent child();",
- " ChildComponent.Builder builder();",
- "}");
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " static interface Builder {",
- " ChildComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- moreThanOneRefToSubcomponent(),
- "test.ChildComponent",
- process("[child(), builder()]")))
- .inFile(componentFile);
- }
-
- @Test
- public void testRefSubCreatorTwiceFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder builder1();",
- " ChildComponent.Builder builder2();",
- "}");
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " static interface Builder {",
- " ChildComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- moreThanOneRefToSubcomponent(),
- "test.ChildComponent", process("[builder1(), builder2()]")))
- .inFile(componentFile);
- }
-
- @Test
- public void testMoreThanOneCreatorFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder1 build();",
- "}");
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " static interface Builder1 {",
- " ChildComponent build();",
- " }",
- "",
- " @Subcomponent.Builder",
- " static interface Builder2 {",
- " ChildComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- componentMessagesFor(SUBCOMPONENT).moreThanOne(),
- process("[test.ChildComponent.Builder1, test.ChildComponent.Builder2]")))
- .inFile(childComponentFile);
- }
-
- @Test
- public void testMoreThanOneCreatorFails_differentTypes() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder build();",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " static interface Builder {",
- " ChildComponent build();",
- " }",
- "",
- " @Subcomponent.Factory",
- " static interface Factory {",
- " ChildComponent create();",
- " }",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- componentMessagesFor(SUBCOMPONENT).moreThanOne(),
- "[test.ChildComponent.Builder, test.ChildComponent.Factory]"))
- .inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorGenericsFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder build();",
- "}");
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder<T> {",
- " ChildComponent build();",
- " }",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.generics()).inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorNotInComponentFails() {
- JavaFileObject builder = preprocessedJavaFile("test.Builder",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent.Builder",
- "interface Builder {}");
- Compilation compilation = compile(builder);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.mustBeInComponent()).inFile(builder);
- }
-
- @Test
- public void testCreatorMissingFactoryMethodFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder builder();",
- "}");
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {}",
- "}");
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.missingFactoryMethod())
- .inFile(childComponentFile);
- }
-
- @Test
- public void testPrivateCreatorFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " private interface Builder {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.isPrivate()).inFile(childComponentFile);
- }
-
- @Test
- public void testNonStaticCreatorFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " abstract class Builder {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining(messages.mustBeStatic()).inFile(childComponentFile);
- }
-
- @Test
- public void testNonAbstractCreatorFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " static class Builder {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.mustBeAbstract())
- .inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorOneConstructorWithArgsFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " static abstract class Builder {",
- " Builder(String unused) {}",
- " }",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.invalidConstructor())
- .inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorMoreThanOneConstructorFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " static abstract class Builder {",
- " Builder() {}",
- " Builder(String unused) {}",
- " }",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.invalidConstructor())
- .inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorEnumFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " enum Builder {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.mustBeClassOrInterface())
- .inFile(childComponentFile);
- }
-
- @Test
- public void testCreatorFactoryMethodReturnsWrongTypeFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " String build();",
- " }",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(messages.factoryMethodMustReturnComponentType())
- .inFile(childComponentFile)
- .onLine(9);
- }
-
- @Test
- public void testInheritedCreatorFactoryMethodReturnsWrongTypeFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " interface Parent {",
- " String build();",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.inheritedFactoryMethodMustReturnComponentType(), process("build")))
- .inFile(childComponentFile)
- .onLine(12);
- }
-
- @Test
- public void testTwoFactoryMethodsFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " ChildComponent build1();",
- " }",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(String.format(messages.twoFactoryMethods(), process("build()")))
- .inFile(childComponentFile)
- .onLine(10);
- }
-
- @Test
- public void testInheritedTwoFactoryMethodsFails() {
- JavaFileObject childComponentFile = preprocessedJavaFile("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " interface Parent {",
- " ChildComponent build();",
- " ChildComponent build1();",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent {}",
- "}");
- Compilation compilation = compile(childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.inheritedTwoFactoryMethods(), process("build()"), process("build1()")))
- .inFile(childComponentFile)
- .onLine(13);
- }
-
- @Test
- public void testMultipleSettersPerTypeFails() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String s() { return \"\"; }",
- "}");
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder childComponentBuilder();",
- "}");
- JavaFileObject childComponentFile =
- javaFileBuilder("test.ChildComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "abstract class ChildComponent {",
- " abstract String s();",
- "")
- .addLinesIf(
- BUILDER,
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " void set1(TestModule s);",
- " void set2(TestModule s);",
- " }")
- .addLinesIf(
- FACTORY,
- " @Subcomponent.Factory",
- " interface Factory {",
- " ChildComponent create(TestModule m1, TestModule m2);",
- " }")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(moduleFile, componentFile, childComponentFile);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(BUILDER)
- ? "[void test.ChildComponent.Builder.set1(test.TestModule), "
- + "void test.ChildComponent.Builder.set2(test.TestModule)]"
- : "[test.TestModule m1, test.TestModule m2]";
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
- .inFile(childComponentFile)
- .onLine(11);
- }
-
- @Test
- public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
- JavaFileObject moduleFile =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String s() { return \"\"; }",
- "}");
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder childComponentBuilder();",
- "}");
- JavaFileObject childComponentFile =
- javaFileBuilder("test.ChildComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "abstract class ChildComponent {",
- " abstract String s();",
- "")
- .addLinesIf(
- BUILDER,
- " interface Parent<T> {",
- " void set1(T t);",
- " }",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends Parent<TestModule> {",
- " ChildComponent build();",
- " void set2(TestModule s);",
- " }")
- .addLinesIf(
- FACTORY,
- " interface Parent<C, T> {",
- " C create(TestModule m1, T t);",
- " }",
- "",
- " @Subcomponent.Factory",
- " interface Factory extends Parent<ChildComponent, TestModule> {}")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(moduleFile, componentFile, childComponentFile);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(BUILDER)
- ? "[void test.ChildComponent.Builder.set1(test.TestModule), "
- + "void test.ChildComponent.Builder.set2(test.TestModule)]"
- : "[test.TestModule m1, test.TestModule t]";
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
- .inFile(childComponentFile)
- .onLine(15);
- }
-
- @Test
- public void testMultipleSettersPerBoundInstanceTypeFails() {
- JavaFileObject componentFile =
- preprocessedJavaFile(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder childComponentBuilder();",
- "}");
- JavaFileObject childComponentFile =
- javaFileBuilder("test.ChildComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.BindsInstance;",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {",
- " abstract String s();",
- "")
- .addLinesIf(
- BUILDER,
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " @BindsInstance void set1(String s);",
- " @BindsInstance void set2(String s);",
- " }")
- .addLinesIf(
- FACTORY,
- " @Subcomponent.Factory",
- " interface Factory {",
- " ChildComponent create(",
- " @BindsInstance String s1, @BindsInstance String s2);",
- " }")
- .addLines( //
- "}")
- .build();
-
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- String firstBinding = creatorKind.equals(FACTORY)
- ? "test.ChildComponent.Factory.create(s1, …)"
- : "@BindsInstance void test.ChildComponent.Builder.set1(String)";
- String secondBinding = creatorKind.equals(FACTORY)
- ? "test.ChildComponent.Factory.create(…, s2)"
- : "@BindsInstance void test.ChildComponent.Builder.set2(String)";
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "java.lang.String is bound multiple times:",
- " " + firstBinding,
- " " + secondBinding,
- " java.lang.String is provided at",
- " test.ChildComponent.s() [test.ParentComponent → test.ChildComponent]"))
- .inFile(componentFile)
- .onLineContaining("interface ParentComponent {");
- }
-
- @Test
- public void testExtraSettersFails() {
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder build();",
- "}");
- JavaFileObject childComponentFile =
- javaFileBuilder("test.ChildComponent")
- .addLines(
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent",
- "abstract class ChildComponent {")
- .addLinesIf(
- BUILDER,
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " void set1(String s);",
- " void set2(Integer s);",
- " }")
- .addLinesIf(
- FACTORY,
- " @Subcomponent.Factory",
- " interface Factory {",
- " ChildComponent create(String s, Integer i);",
- " }")
- .addLines( //
- "}")
- .build();
- Compilation compilation = compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- String elements =
- creatorKind.equals(FACTORY)
- ? "[String s, Integer i]"
- : "[void test.ChildComponent.Builder.set1(String),"
- + " void test.ChildComponent.Builder.set2(Integer)]";
- assertThat(compilation)
- .hadErrorContaining(
- String.format(
- messages.extraSetters(),
- elements))
- .inFile(childComponentFile)
- .onLine(9);
- }
-
- @Test
- public void testMissingSettersFail() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " TestModule(String unused) {}",
- " @Provides String s() { return null; }",
- "}");
- JavaFileObject module2File = JavaFileObjects.forSourceLines("test.Test2Module",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class Test2Module {",
- " @Provides Integer i() { return null; }",
- "}");
- JavaFileObject module3File = JavaFileObjects.forSourceLines("test.Test3Module",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class Test3Module {",
- " Test3Module(String unused) {}",
- " @Provides Double d() { return null; }",
- "}");
- JavaFileObject componentFile = preprocessedJavaFile("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent.Builder build();",
- "}");
- JavaFileObject childComponentFile =
- preprocessedJavaFile(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = {TestModule.class, Test2Module.class, Test3Module.class})",
- "interface ChildComponent {",
- " String string();",
- " Integer integer();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " ChildComponent build();",
- " }",
- "}");
- Compilation compilation =
- compile(moduleFile, module2File, module3File, componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- // Ignores Test2Module because we can construct it ourselves.
- // TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
- String.format(messages.missingSetters(), "[test.TestModule, test.Test3Module]"))
- .inFile(childComponentFile)
- .onLine(11);
- }
-
- @Test
- public void covariantFactoryMethodReturnType() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject subcomponent =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface HasSupertype extends Supertype {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Supertype build();",
- " }",
- "}");
-
- Compilation compilation = compile(foo, supertype, subcomponent);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
- @Test
- public void covariantFactoryMethodReturnType_hasNewMethod() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject subcomponent =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface HasSupertype extends Supertype {",
- " Bar bar();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Supertype build();",
- " }",
- "}");
-
- Compilation compilation = compile(foo, bar, supertype, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining(
- process(
- "test.HasSupertype.Builder.build() returns test.Supertype, but test.HasSupertype "
- + "declares additional component method(s): bar(). In order to provide "
- + "type-safe access to these methods, override build() to return "
- + "test.HasSupertype"))
- .inFile(subcomponent)
- .onLine(11);
- }
-
- @Test
- public void covariantFactoryMethodReturnType_hasNewMethod_buildMethodInherited() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject supertype =
- JavaFileObjects.forSourceLines(
- "test.Supertype",
- "package test;",
- "",
- "interface Supertype {",
- " Foo foo();",
- "}");
-
- JavaFileObject creatorSupertype =
- preprocessedJavaFile(
- "test.CreatorSupertype",
- "package test;",
- "",
- "interface CreatorSupertype {",
- " Supertype build();",
- "}");
-
- JavaFileObject subcomponent =
- preprocessedJavaFile(
- "test.HasSupertype",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface HasSupertype extends Supertype {",
- " Bar bar();",
- "",
- " @Subcomponent.Builder",
- " interface Builder extends CreatorSupertype {}",
- "}");
-
- Compilation compilation = compile(foo, bar, supertype, creatorSupertype, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .hadWarningContaining(
- process(
- "[test.CreatorSupertype.build()] test.HasSupertype.Builder.build() returns "
- + "test.Supertype, but test.HasSupertype declares additional component "
- + "method(s): bar(). In order to provide type-safe access to these methods, "
- + "override build() to return test.HasSupertype"));
- }
-}
diff --git a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
deleted file mode 100644
index ad08160..0000000
--- a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
+++ /dev/null
@@ -1,1165 +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;
-
-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.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Collection;
-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 SubcomponentValidationTest {
- @Parameters(name = "{0}")
- public static Collection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public SubcomponentValidationTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test public void factoryMethod_missingModulesWithParameters() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent();",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ModuleWithParameters.class)",
- "interface ChildComponent {",
- " Object object();",
- "}");
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ModuleWithParameters",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class ModuleWithParameters {",
- " private final Object object;",
- "",
- " ModuleWithParameters(Object object) {",
- " this.object = object;",
- " }",
- "",
- " @Provides Object object() {",
- " return object;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(componentFile, childComponentFile, moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.ChildComponent requires modules which have no visible default constructors. "
- + "Add the following modules as parameters to this method: "
- + "test.ModuleWithParameters")
- .inFile(componentFile)
- .onLineContaining("ChildComponent newChildComponent();");
- }
-
- @Test
- public void factoryMethod_grandchild() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent();",
- "}");
- JavaFileObject childComponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {",
- " GrandchildComponent newGrandchildComponent();",
- "}");
- JavaFileObject grandchildComponent =
- JavaFileObjects.forSourceLines(
- "test.GrandchildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = GrandchildModule.class)",
- "interface GrandchildComponent {",
- " Object object();",
- "}");
- JavaFileObject grandchildModule =
- JavaFileObjects.forSourceLines(
- "test.GrandchildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class GrandchildModule {",
- " private final Object object;",
- "",
- " GrandchildModule(Object object) {",
- " this.object = object;",
- " }",
- "",
- " @Provides Object object() {",
- " return object;",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(component, childComponent, grandchildComponent, grandchildModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "[test.ChildComponent.newGrandchildComponent()] "
- + "test.GrandchildComponent requires modules which have no visible default "
- + "constructors. Add the following modules as parameters to this method: "
- + "test.GrandchildModule")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test public void factoryMethod_nonModuleParameter() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent(String someRandomString);",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Subcomponent factory methods may only accept modules, but java.lang.String is not.")
- .inFile(componentFile)
- .onLine(7)
- .atColumn(43);
- }
-
- @Test public void factoryMethod_duplicateParameter() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class TestModule {}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent(TestModule testModule1, TestModule testModule2);",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "interface ChildComponent {}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(moduleFile, componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "A module may only occur once an an argument in a Subcomponent factory method, "
- + "but test.TestModule was already passed.")
- .inFile(componentFile)
- .onLine(7)
- .atColumn(71);
- }
-
- @Test public void factoryMethod_superflouousModule() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module",
- "final class TestModule {}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent(TestModule testModule);",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface ChildComponent {}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(moduleFile, componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "test.TestModule is present as an argument to the test.ChildComponent factory method, "
- + "but is not one of the modules used to implement the subcomponent.")
- .inFile(componentFile)
- .onLine(7);
- }
-
- @Test public void missingBinding() {
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class TestModule {",
- " @Provides String provideString(int i) {",
- " return Integer.toString(i);",
- " }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " ChildComponent newChildComponent();",
- "}");
- JavaFileObject childComponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = TestModule.class)",
- "interface ChildComponent {",
- " String getString();",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(moduleFile, componentFile, childComponentFile);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "java.lang.Integer cannot be provided without an @Inject constructor or an "
- + "@Provides-annotated method")
- .inFile(componentFile)
- .onLineContaining("interface TestComponent");
- }
-
- @Test public void subcomponentOnConcreteType() {
- JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.NotASubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "final class NotASubcomponent {}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(subcomponentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("interface");
- }
-
- @Test public void scopeMismatch() {
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Component",
- "@Singleton",
- "interface ParentComponent {",
- " ChildComponent childComponent();",
- "}");
- JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines("test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Object getObject();",
- "}");
- JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "final class ChildModule {",
- " @Provides @Singleton Object provideObject() { return null; }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(componentFile, subcomponentFile, moduleFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("@Singleton");
- }
-
- @Test
- public void delegateFactoryNotCreatedForSubcomponentWhenProviderExistsInParent() {
- JavaFileObject parentComponentFile =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface ParentComponent {",
- " ChildComponent childComponent();",
- " Dep1 getDep1();",
- " Dep2 getDep2();",
- "}");
- JavaFileObject childComponentFile =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Object getObject();",
- "}");
- JavaFileObject childModuleFile =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "final class ChildModule {",
- " @Provides Object provideObject(A a) { return null; }",
- "}");
- JavaFileObject aFile =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class A {",
- " @Inject public A(NeedsDep1 a, Dep1 b, Dep2 c) { }",
- " @Inject public void methodA() { }",
- "}");
- JavaFileObject needsDep1File =
- JavaFileObjects.forSourceLines(
- "test.NeedsDep1",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class NeedsDep1 {",
- " @Inject public NeedsDep1(Dep1 d) { }",
- "}");
- JavaFileObject dep1File =
- JavaFileObjects.forSourceLines(
- "test.Dep1",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class Dep1 {",
- " @Inject public Dep1() { }",
- " @Inject public void dep1Method() { }",
- "}");
- JavaFileObject dep2File =
- JavaFileObjects.forSourceLines(
- "test.Dep2",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class Dep2 {",
- " @Inject public Dep2() { }",
- " @Inject public void dep2Method() { }",
- "}");
-
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerParentComponent")
- .addLines(
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParentComponent implements ParentComponent {")
- .addLinesIn(
- DEFAULT_MODE,
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.dep1Provider = DoubleCheck.provider(Dep1_Factory.create());",
- " this.dep2Provider = DoubleCheck.provider(Dep2_Factory.create());",
- " }",
- "")
- .addLines(
- " @Override", //
- " public Dep1 getDep1() {")
- .addLinesIn(
- FAST_INIT_MODE,
- " Object local = dep1;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = dep1;",
- " if (local instanceof MemoizedSentinel) {",
- " local = injectDep1(Dep1_Factory.newInstance());",
- " dep1 = DoubleCheck.reentrantCheck(dep1, local);",
- " }",
- " }",
- " }",
- " return (Dep1) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return dep1Provider.get();")
- .addLines(
- " }", //
- "",
- " @Override",
- " public Dep2 getDep2() {")
- .addLinesIn(
- FAST_INIT_MODE,
- " Object local = dep2;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = dep2;",
- " if (local instanceof MemoizedSentinel) {",
- " local = injectDep2(Dep2_Factory.newInstance());",
- " dep2 = DoubleCheck.reentrantCheck(dep2, local);",
- " }",
- " }",
- " }",
- " return (Dep2) local;")
- .addLinesIn(
- DEFAULT_MODE, //
- " return dep2Provider.get();")
- .addLines(
- " }",
- "",
- " @Override",
- " public ChildComponent childComponent() {",
- " return new ChildComponentImpl();",
- " }",
- "")
- .addLinesIn(
- FAST_INIT_MODE,
- " @CanIgnoreReturnValue",
- " private Dep1 injectDep1(Dep1 instance) {",
- " Dep1_MembersInjector.injectDep1Method(instance);",
- " return instance;",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private Dep2 injectDep2(Dep2 instance) {",
- " Dep2_MembersInjector.injectDep2Method(instance);",
- " return instance;",
- " }")
- .addLines(
- "",
- " private final class ChildComponentImpl implements ChildComponent {",
- " private final ChildModule childModule;",
- "",
- " private ChildComponentImpl() {",
- " this.childModule = new ChildModule();",
- " }",
- "")
- .addLinesIn(
- DEFAULT_MODE,
- " private NeedsDep1 getNeedsDep1() {",
- " return new NeedsDep1(DaggerParentComponent.this.dep1Provider.get());",
- " }")
- .addLinesIn(
- FAST_INIT_MODE,
- " private NeedsDep1 getNeedsDep1() {",
- " return new NeedsDep1(DaggerParentComponent.this.getDep1());",
- " }")
- .addLines(
- " private A getA() {",
- " return injectA(",
- " A_Factory.newInstance(",
- " getNeedsDep1(),")
- .addLinesIn(
- DEFAULT_MODE,
- " DaggerParentComponent.this.dep1Provider.get(),",
- " DaggerParentComponent.this.dep2Provider.get()));")
- .addLinesIn(
- FAST_INIT_MODE,
- " DaggerParentComponent.this.getDep1(),",
- " DaggerParentComponent.this.getDep2()));")
- .addLines(
- " }",
- "",
- " @Override",
- " public Object getObject() {",
- " return ChildModule_ProvideObjectFactory.provideObject(",
- " childModule, getA());",
- " }",
- "",
- " @CanIgnoreReturnValue",
- " private A injectA(A instance) {",
- " A_MembersInjector.injectMethodA(instance);",
- " return instance;",
- " }",
- " }",
- "}")
- .build();
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(
- parentComponentFile,
- childComponentFile,
- childModuleFile,
- aFile,
- needsDep1File,
- dep1File,
- dep2File);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParentComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void multipleSubcomponentsWithSameSimpleNamesCanExistInSameComponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " Foo.Sub newInstanceSubcomponent();",
- " NoConflict newNoConflictSubcomponent();",
- "}");
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "interface Foo {",
- " @Subcomponent interface Sub {",
- " Bar.Sub newBarSubcomponent();",
- " }",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "interface Bar {",
- " @Subcomponent interface Sub {",
- " test.subpackage.Sub newSubcomponentInSubpackage();",
- " }",
- "}");
- JavaFileObject baz =
- JavaFileObjects.forSourceLines(
- "test.subpackage.Sub",
- "package test.subpackage;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent public interface Sub {}");
- JavaFileObject noConflict =
- JavaFileObjects.forSourceLines(
- "test.NoConflict",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent interface NoConflict {}");
-
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "test.DaggerParentComponent",
- "package test;",
- "",
- "import test.subpackage.Sub;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParentComponent implements ParentComponent {",
- " @Override",
- " public Foo.Sub newInstanceSubcomponent() {",
- " return new F_SubImpl();",
- " }",
- "",
- " @Override",
- " public NoConflict newNoConflictSubcomponent() {",
- " return new NoConflictImpl();",
- " }",
- "",
- " static final class Builder {",
- " public ParentComponent build() {",
- " return new DaggerParentComponent();",
- " }",
- " }",
- "",
- " private final class F_SubImpl implements Foo.Sub {",
- " @Override",
- " public Bar.Sub newBarSubcomponent() {",
- " return new B_SubImpl();",
- " }",
- "",
- " private final class B_SubImpl implements Bar.Sub {",
- " @Override",
- " public Sub newSubcomponentInSubpackage() {",
- " return new ts_SubImpl();",
- " }",
- "",
- " private final class ts_SubImpl implements Sub {}",
- " }",
- " }",
- "",
- " private final class NoConflictImpl implements NoConflict {}",
- "}");
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(parent, foo, bar, baz, noConflict);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParentComponent")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void subcomponentSimpleNamesDisambiguated() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " Sub newSubcomponent();",
- "}");
- JavaFileObject sub =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent interface Sub {",
- " test.deep.many.levels.that.match.test.Sub newDeepSubcomponent();",
- "}");
- JavaFileObject deepSub =
- JavaFileObjects.forSourceLines(
- "test.deep.many.levels.that.match.test.Sub",
- "package test.deep.many.levels.that.match.test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent public interface Sub {}");
-
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "test.DaggerParentComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParentComponent implements ParentComponent {",
- " @Override",
- " public Sub newSubcomponent() {",
- " return new t_SubImpl();",
- " }",
- "",
- " static final class Builder {",
- " public ParentComponent build() {",
- " return new DaggerParentComponent();",
- " }",
- " }",
- "",
- " private final class t_SubImpl implements Sub {",
- " @Override",
- " public test.deep.many.levels.that.match.test.Sub newDeepSubcomponent() {",
- " return new tdmltmt_SubImpl();",
- " }",
- "",
- " private final class tdmltmt_SubImpl implements ",
- " test.deep.many.levels.that.match.test.Sub {",
- " private tdmltmt_SubImpl() {}",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParentComponent")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void subcomponentSimpleNamesDisambiguatedInRoot() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "ParentComponent",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " Sub newSubcomponent();",
- "}");
- JavaFileObject sub =
- JavaFileObjects.forSourceLines(
- "Sub",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent interface Sub {",
- " test.deep.many.levels.that.match.test.Sub newDeepSubcomponent();",
- "}");
- JavaFileObject deepSub =
- JavaFileObjects.forSourceLines(
- "test.deep.many.levels.that.match.test.Sub",
- "package test.deep.many.levels.that.match.test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent public interface Sub {}");
-
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "DaggerParentComponent",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParentComponent implements ParentComponent {",
- " @Override",
- " public Sub newSubcomponent() {",
- " return new $_SubImpl();",
- " }",
- "",
- " private final class $_SubImpl implements Sub {",
- " private $_SubImpl() {}",
- "",
- " @Override",
- " public test.deep.many.levels.that.match.test.Sub newDeepSubcomponent() {",
- " return new tdmltmt_SubImpl();",
- " }",
- "",
- " private final class tdmltmt_SubImpl implements ",
- " test.deep.many.levels.that.match.test.Sub {",
- " private tdmltmt_SubImpl() {}",
- " }",
- " }",
- "}",
- "");
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("DaggerParentComponent")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void subcomponentImplNameUsesFullyQualifiedClassNameIfNecessary() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface ParentComponent {",
- " top1.a.b.c.d.E.F.Sub top1();",
- " top2.a.b.c.d.E.F.Sub top2();",
- "}");
- JavaFileObject top1 =
- JavaFileObjects.forSourceLines(
- "top1.a.b.c.d.E",
- "package top1.a.b.c.d;",
- "",
- "import dagger.Subcomponent;",
- "",
- "public interface E {",
- " interface F {",
- " @Subcomponent interface Sub {}",
- " }",
- "}");
- JavaFileObject top2 =
- JavaFileObjects.forSourceLines(
- "top2.a.b.c.d.E",
- "package top2.a.b.c.d;",
- "",
- "import dagger.Subcomponent;",
- "",
- "public interface E {",
- " interface F {",
- " @Subcomponent interface Sub {}",
- " }",
- "}");
-
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "test.DaggerParentComponent",
- "package test;",
- "",
- "import top1.a.b.c.d.E;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerParentComponent implements ParentComponent {",
- " @Override",
- " public E.F.Sub top1() {",
- " return new F_SubImpl();",
- " }",
- "",
- " @Override",
- " public top2.a.b.c.d.E.F.Sub top2() {",
- " return new F2_SubImpl();",
- " }",
- "",
- " private final class F_SubImpl implements E.F.Sub {",
- " private F_SubImpl() {}",
- " }",
- " private final class F2_SubImpl implements top2.a.b.c.d.E.F.Sub {",
- " private F2_SubImpl() {}",
- " }",
- "}");
-
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, top1, top2);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParentComponent")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void parentComponentNameShouldNotBeDisambiguatedWhenItConflictsWithASubcomponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface C {",
- " test.Foo.C newInstanceC();",
- "}");
- JavaFileObject subcomponentWithSameSimpleNameAsParent =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "interface Foo {",
- " @Subcomponent interface C {}",
- "}");
-
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "test.DaggerC",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerC implements C {",
- " @Override",
- " public Foo.C newInstanceC() {",
- " return new F_CImpl();",
- " }",
- "",
- " private final class F_CImpl implements Foo.C {}",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(parent, subcomponentWithSameSimpleNameAsParent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerC")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void subcomponentBuilderNamesShouldNotConflict() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.Subcomponent;",
- "",
- "@Component",
- "interface C {",
- " Foo.Sub.Builder fooBuilder();",
- " Bar.Sub.Builder barBuilder();",
- "",
- " interface Foo {",
- " @Subcomponent",
- " interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- " }",
- " }",
- "",
- " interface Bar {",
- " @Subcomponent",
- " interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- " }",
- " }",
- "}");
- JavaFileObject componentGeneratedFile =
- JavaFileObjects.forSourceLines(
- "test.DaggerC",
- "package test;",
- "",
- IMPORT_GENERATED_ANNOTATION,
- "",
- GENERATED_ANNOTATION,
- "final class DaggerC implements C {",
- " @Override",
- " public C.Foo.Sub.Builder fooBuilder() {",
- " return new F_SubBuilder();",
- " }",
- "",
- " @Override",
- " public C.Bar.Sub.Builder barBuilder() {",
- " return new B_SubBuilder();",
- " }",
- "",
- // 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",
- " public C.Foo.Sub build() {",
- " return new F_SubImpl();",
- " }",
- " }",
- "",
- " private final class F_SubImpl implements C.Foo.Sub {",
- " private F_SubImpl() {}",
- " }",
- "",
- " private final class B_SubBuilder implements C.Bar.Sub.Builder {",
- " @Override",
- " public C.Bar.Sub build() {",
- " return new B_SubImpl();",
- " }",
- " }",
- "",
- " private final class B_SubImpl implements C.Bar.Sub {",
- " private B_SubImpl() {}",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerC")
- .containsElementsIn(componentGeneratedFile);
- }
-
- @Test
- public void duplicateBindingWithSubcomponentDeclaration() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module(subcomponents = Sub.class)",
- "class TestModule {",
- " @Provides Sub.Builder providesConflictsWithModuleSubcomponents() { return null; }",
- " @Provides Object usesSubcomponentBuilder(Sub.Builder builder) {",
- " return new Builder().toString();",
- " }",
- "}");
-
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Sub {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Sub build();",
- " }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = TestModule.class)",
- "interface C {",
- " Object dependsOnBuilder();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .withOptions(compilerMode.javacopts())
- .compile(module, component, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("test.Sub.Builder is bound multiple times:");
- assertThat(compilation)
- .hadErrorContaining(
- "@Provides test.Sub.Builder "
- + "test.TestModule.providesConflictsWithModuleSubcomponents()");
- assertThat(compilation)
- .hadErrorContaining("@Module(subcomponents = test.Sub.class) for test.TestModule");
- }
-
- @Test
- public void subcomponentDependsOnGeneratedType() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Child.Builder childBuilder();",
- "}");
-
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child extends ChildSupertype {",
- " @Subcomponent.Builder",
- " interface Builder {",
- " Child build();",
- " }",
- "}");
-
- JavaFileObject childSupertype =
- JavaFileObjects.forSourceLines(
- "test.ChildSupertype",
- "package test;",
- "",
- "interface ChildSupertype {",
- " GeneratedType generatedType();",
- "}");
-
- Compilation compilation =
- daggerCompiler(
- new GeneratingProcessor(
- "test.GeneratedType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class GeneratedType {",
- " @Inject GeneratedType() {}",
- "}"))
- .compile(parent, child, childSupertype);
- assertThat(compilation).succeededWithoutWarnings();
- }
-}
diff --git a/javatests/dagger/internal/codegen/SwitchingProviderTest.java b/javatests/dagger/internal/codegen/SwitchingProviderTest.java
deleted file mode 100644
index 2898f2e..0000000
--- a/javatests/dagger/internal/codegen/SwitchingProviderTest.java
+++ /dev/null
@@ -1,600 +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;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class SwitchingProviderTest {
- @Test
- public void switchingProviderTest() {
- ImmutableList.Builder<JavaFileObject> javaFileObjects = ImmutableList.builder();
- StringBuilder entryPoints = new StringBuilder();
- for (int i = 0; i <= 100; i++) {
- String bindingName = "Binding" + i;
- javaFileObjects.add(
- JavaFileObjects.forSourceLines(
- "test." + bindingName,
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "final class " + bindingName + " {",
- " @Inject",
- " " + bindingName + "() {}",
- "}"));
- entryPoints.append(String.format(" Provider<%1$s> get%1$sProvider();\n", bindingName));
- }
-
- javaFileObjects.add(
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface TestComponent {",
- entryPoints.toString(),
- "}"));
-
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " private T get0() {",
- " switch (id) {",
- " case 0: return (T) new Binding0();",
- " case 1: return (T) new Binding1();",
- " case 2: return (T) new Binding2();",
- " case 3: return (T) new Binding3();",
- " case 4: return (T) new Binding4();",
- " case 5: return (T) new Binding5();",
- " case 6: return (T) new Binding6();",
- " case 7: return (T) new Binding7();",
- " case 8: return (T) new Binding8();",
- " case 9: return (T) new Binding9();",
- " case 10: return (T) new Binding10();",
- " case 11: return (T) new Binding11();",
- " case 12: return (T) new Binding12();",
- " case 13: return (T) new Binding13();",
- " case 14: return (T) new Binding14();",
- " case 15: return (T) new Binding15();",
- " case 16: return (T) new Binding16();",
- " case 17: return (T) new Binding17();",
- " case 18: return (T) new Binding18();",
- " case 19: return (T) new Binding19();",
- " case 20: return (T) new Binding20();",
- " case 21: return (T) new Binding21();",
- " case 22: return (T) new Binding22();",
- " case 23: return (T) new Binding23();",
- " case 24: return (T) new Binding24();",
- " case 25: return (T) new Binding25();",
- " case 26: return (T) new Binding26();",
- " case 27: return (T) new Binding27();",
- " case 28: return (T) new Binding28();",
- " case 29: return (T) new Binding29();",
- " case 30: return (T) new Binding30();",
- " case 31: return (T) new Binding31();",
- " case 32: return (T) new Binding32();",
- " case 33: return (T) new Binding33();",
- " case 34: return (T) new Binding34();",
- " case 35: return (T) new Binding35();",
- " case 36: return (T) new Binding36();",
- " case 37: return (T) new Binding37();",
- " case 38: return (T) new Binding38();",
- " case 39: return (T) new Binding39();",
- " case 40: return (T) new Binding40();",
- " case 41: return (T) new Binding41();",
- " case 42: return (T) new Binding42();",
- " case 43: return (T) new Binding43();",
- " case 44: return (T) new Binding44();",
- " case 45: return (T) new Binding45();",
- " case 46: return (T) new Binding46();",
- " case 47: return (T) new Binding47();",
- " case 48: return (T) new Binding48();",
- " case 49: return (T) new Binding49();",
- " case 50: return (T) new Binding50();",
- " case 51: return (T) new Binding51();",
- " case 52: return (T) new Binding52();",
- " case 53: return (T) new Binding53();",
- " case 54: return (T) new Binding54();",
- " case 55: return (T) new Binding55();",
- " case 56: return (T) new Binding56();",
- " case 57: return (T) new Binding57();",
- " case 58: return (T) new Binding58();",
- " case 59: return (T) new Binding59();",
- " case 60: return (T) new Binding60();",
- " case 61: return (T) new Binding61();",
- " case 62: return (T) new Binding62();",
- " case 63: return (T) new Binding63();",
- " case 64: return (T) new Binding64();",
- " case 65: return (T) new Binding65();",
- " case 66: return (T) new Binding66();",
- " case 67: return (T) new Binding67();",
- " case 68: return (T) new Binding68();",
- " case 69: return (T) new Binding69();",
- " case 70: return (T) new Binding70();",
- " case 71: return (T) new Binding71();",
- " case 72: return (T) new Binding72();",
- " case 73: return (T) new Binding73();",
- " case 74: return (T) new Binding74();",
- " case 75: return (T) new Binding75();",
- " case 76: return (T) new Binding76();",
- " case 77: return (T) new Binding77();",
- " case 78: return (T) new Binding78();",
- " case 79: return (T) new Binding79();",
- " case 80: return (T) new Binding80();",
- " case 81: return (T) new Binding81();",
- " case 82: return (T) new Binding82();",
- " case 83: return (T) new Binding83();",
- " case 84: return (T) new Binding84();",
- " case 85: return (T) new Binding85();",
- " case 86: return (T) new Binding86();",
- " case 87: return (T) new Binding87();",
- " case 88: return (T) new Binding88();",
- " case 89: return (T) new Binding89();",
- " case 90: return (T) new Binding90();",
- " case 91: return (T) new Binding91();",
- " case 92: return (T) new Binding92();",
- " case 93: return (T) new Binding93();",
- " case 94: return (T) new Binding94();",
- " case 95: return (T) new Binding95();",
- " case 96: return (T) new Binding96();",
- " case 97: return (T) new Binding97();",
- " case 98: return (T) new Binding98();",
- " case 99: return (T) new Binding99();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private T get1() {",
- " switch (id) {",
- " case 100: return (T) new Binding100();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- "",
- " @Override",
- " public T get() {",
- " switch (id / 100) {",
- " case 0: return get0();",
- " case 1: return get1();",
- " default: throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(javaFileObjects.build());
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void unscopedBinds() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String s() {",
- " return new String();",
- " }",
- "",
- " @Binds CharSequence c(String s);",
- " @Binds Object o(CharSequence c);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<Object> objectProvider();",
- " Provider<CharSequence> charSequenceProvider();",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private volatile Provider<String> sProvider;",
- "",
- " private Provider<String> getStringProvider() {",
- " Object local = sProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " sProvider = (Provider<String>) local;",
- " }",
- " return (Provider<String>) local;",
- " }",
- "",
- " @Override",
- " public Provider<Object> objectProvider() {",
- " return (Provider) getStringProvider();",
- " }",
- "",
- " @Override",
- " public Provider<CharSequence> charSequenceProvider() {",
- " return (Provider) getStringProvider();",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) TestModule_SFactory.s();",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}"));
- }
-
- @Test
- public void scopedBinds() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Singleton;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static String s() {",
- " return new String();",
- " }",
- "",
- " @Binds @Singleton Object o(CharSequence s);",
- " @Binds @Singleton CharSequence c(String s);",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<Object> objectProvider();",
- " Provider<CharSequence> charSequenceProvider();",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private volatile Object charSequence = new MemoizedSentinel();",
- " private volatile Provider<CharSequence> cProvider;",
- "",
- " private CharSequence getCharSequence() {",
- " Object local = charSequence;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = charSequence;",
- " if (local instanceof MemoizedSentinel) {",
- " local = TestModule_SFactory.s();",
- " charSequence = DoubleCheck.reentrantCheck(charSequence, local);",
- " }",
- " }",
- " }",
- " return (CharSequence) local;",
- " }",
- "",
- " @Override",
- " public Provider<Object> objectProvider() {",
- " return (Provider) charSequenceProvider();",
- " }",
- "",
- " @Override",
- " public Provider<CharSequence> charSequenceProvider() {",
- " Object local = cProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " cProvider = (Provider<CharSequence>) local;",
- " }",
- " return (Provider<CharSequence>) local;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0:",
- " return (T) DaggerTestComponent.this.getCharSequence();",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}"));
- }
-
- @Test
- public void emptyMultibindings_avoidSwitchProviders() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.multibindings.Multibinds;",
- "import dagger.Module;",
- "import java.util.Map;",
- "import java.util.Set;",
- "",
- "@Module",
- "interface TestModule {",
- " @Multibinds Set<String> set();",
- " @Multibinds Map<String, String> map();",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import java.util.Set;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<Set<String>> setProvider();",
- " Provider<Map<String, String>> mapProvider();",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @Override",
- " public Provider<Set<String>> setProvider() {",
- " return SetFactory.<String>empty();",
- " }",
- "",
- " @Override",
- " public Provider<Map<String, String>> mapProvider() {",
- " return MapFactory.<String, String>emptyMapProvider();",
- " }",
- "}"));
- }
-
- @Test
- public void memberInjectors() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "class Foo {}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.MembersInjector;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface TestComponent {",
- " Provider<MembersInjector<Foo>> providerOfMembersInjector();",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(foo, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " private Provider<MembersInjector<Foo>> fooMembersInjectorProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.fooMembersInjectorProvider = ",
- " InstanceFactory.create(MembersInjectors.<Foo>noOp());",
- " }",
- "",
- " @Override",
- " public Provider<MembersInjector<Foo>> providerOfMembersInjector() {",
- " return fooMembersInjectorProvider;",
- " }",
- "}"));
- }
-
- @Test
- public void optionals() {
- JavaFileObject present =
- JavaFileObjects.forSourceLines(
- "test.Present",
- "package test;",
- "",
- "class Present {}");
- JavaFileObject absent =
- JavaFileObjects.forSourceLines(
- "test.Absent",
- "package test;",
- "",
- "class Absent {}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.BindsOptionalOf;",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @BindsOptionalOf Present bindOptionalOfPresent();",
- " @BindsOptionalOf Absent bindOptionalOfAbsent();",
- "",
- " @Provides static Present p() { return new Present(); }",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Optional;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " Provider<Optional<Present>> providerOfOptionalOfPresent();",
- " Provider<Optional<Absent>> providerOfOptionalOfAbsent();",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(present, absent, module, component);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- GENERATED_ANNOTATION,
- "final class DaggerTestComponent implements TestComponent {",
- " @SuppressWarnings(\"rawtypes\")",
- " private static final Provider ABSENT_JDK_OPTIONAL_PROVIDER =",
- " InstanceFactory.create(Optional.empty());",
- "",
- " private volatile Provider<Optional<Present>> optionalOfPresentProvider;",
- "",
- " private Provider<Optional<Absent>> optionalOfAbsentProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.optionalOfAbsentProvider = absentJdkOptionalProvider();",
- " }",
- "",
- " @Override",
- " public Provider<Optional<Present>> providerOfOptionalOfPresent() {",
- " Object local = optionalOfPresentProvider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(0);",
- " optionalOfPresentProvider = (Provider<Optional<Present>>) local;",
- " }",
- " return (Provider<Optional<Present>>) local;",
- " }",
- "",
- " @Override",
- " public Provider<Optional<Absent>> providerOfOptionalOfAbsent() {",
- " return optionalOfAbsentProvider;",
- " }",
- "",
- " private static <T> Provider<Optional<T>> absentJdkOptionalProvider() {",
- " @SuppressWarnings(\"unchecked\")",
- " Provider<Optional<T>> provider = ",
- " (Provider<Optional<T>>) ABSENT_JDK_OPTIONAL_PROVIDER;",
- " return provider;",
- " }",
- "",
- " private final class SwitchingProvider<T> implements Provider<T> {",
- " @SuppressWarnings(\"unchecked\")",
- " @Override",
- " public T get() {",
- " switch (id) {",
- " case 0: // java.util.Optional<test.Present>",
- " return (T) Optional.of(TestModule_PFactory.p());",
- " default:",
- " throw new AssertionError(id);",
- " }",
- " }",
- " }",
- "}"));
- }
-
- private Compiler compilerWithAndroidMode() {
- return javac()
- .withProcessors(new ComponentProcessor())
- .withOptions(CompilerMode.FAST_INIT_MODE.javacopts());
- }
-}
diff --git a/javatests/dagger/internal/codegen/TestUtils.java b/javatests/dagger/internal/codegen/TestUtils.java
deleted file mode 100644
index 69b27511..0000000
--- a/javatests/dagger/internal/codegen/TestUtils.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;
-
-import com.google.common.base.Joiner;
-import java.util.regex.Pattern;
-
-/** Utility methods useful for codegen tests. */
-final class TestUtils {
-
- private static final Joiner MESSAGE_JOINER = Joiner.on("\n ");
-
- /**
- * Returns the lines joined by {@code "\n "}. Useful for passing to {@link
- * com.google.testing.compile.CompilationSubject#hadErrorContaining(String)}, etc.
- */
- static String message(String... lines) {
- return MESSAGE_JOINER.join(lines);
- }
-
- /**
- * Returns a pattern that matches strings that end with the lines joined by {@code "\n "}. Useful
- * for passing to {@link
- * com.google.testing.compile.CompilationSubject#hadErrorContainingMatch(Pattern)}, etc.
- */
- static Pattern endsWithMessage(String... lines) {
- return Pattern.compile(Pattern.quote(message(lines)) + "$");
- }
-}
diff --git a/javatests/dagger/internal/codegen/TypeProtoConverterTest.java b/javatests/dagger/internal/codegen/TypeProtoConverterTest.java
deleted file mode 100644
index 8c8628c..0000000
--- a/javatests/dagger/internal/codegen/TypeProtoConverterTest.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.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
deleted file mode 100644
index b0f2f2f..0000000
--- a/javatests/dagger/internal/codegen/ValidationReportTest.java
+++ /dev/null
@@ -1,131 +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;
-
-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.common.collect.ImmutableSet;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.ValidationReport.Builder;
-import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.TypeElement;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ValidationReportTest {
- private static final JavaFileObject TEST_CLASS_FILE =
- JavaFileObjects.forSourceLines("test.TestClass",
- "package test;",
- "",
- "final class TestClass {}");
-
- @Test
- public void basicReport() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error");
- reportBuilder.build().printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("simple error").inFile(TEST_CLASS_FILE).onLine(3);
- }
-
- @Test
- public void messageOnDifferentElement() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error", getTypeElement(String.class));
- reportBuilder.build().printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("[java.lang.String] simple error")
- .inFile(TEST_CLASS_FILE)
- .onLine(3);
- }
-
- @Test
- public void subreport() {
- Compilation compilation =
- javac()
- .withProcessors(
- new SimpleTestProcessor() {
- @Override
- void test() {
- Builder<TypeElement> reportBuilder =
- ValidationReport.about(getTypeElement("test.TestClass"));
- reportBuilder.addError("simple error");
- ValidationReport<TypeElement> parentReport =
- ValidationReport.about(getTypeElement(String.class))
- .addSubreport(reportBuilder.build())
- .build();
- assertThat(parentReport.isClean()).isFalse();
- parentReport.printMessagesTo(processingEnv.getMessager());
- }
- })
- .compile(TEST_CLASS_FILE);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("simple error").inFile(TEST_CLASS_FILE).onLine(3);
- }
-
- private static abstract class SimpleTestProcessor extends AbstractProcessor {
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of("*");
- }
-
- @Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- test();
- return false;
- }
-
- protected final TypeElement getTypeElement(Class<?> clazz) {
- return getTypeElement(clazz.getCanonicalName());
- }
-
- protected final TypeElement getTypeElement(String canonicalName) {
- return processingEnv.getElementUtils().getTypeElement(canonicalName);
- }
-
- abstract void test();
- }
-}
diff --git a/javatests/dagger/internal/codegen/javapoet/BUILD b/javatests/dagger/internal/codegen/javapoet/BUILD
deleted file mode 100644
index 99c11bd..0000000
--- a/javatests/dagger/internal/codegen/javapoet/BUILD
+++ /dev/null
@@ -1,37 +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 for dagger.internal.codegen.javapoet
-
-package(default_visibility = ["//:src"])
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
-
-GenJavaTests(
- name = "javapoet_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- 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",
- ],
-)
diff --git a/javatests/dagger/internal/codegen/javapoet/CodeBlocksTest.java b/javatests/dagger/internal/codegen/javapoet/CodeBlocksTest.java
deleted file mode 100644
index ee3681e..0000000
--- a/javatests/dagger/internal/codegen/javapoet/CodeBlocksTest.java
+++ /dev/null
@@ -1,81 +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.javapoet;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.javapoet.CodeBlocks.javadocLinkTo;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static javax.lang.model.element.ElementKind.METHOD;
-
-import com.google.testing.compile.CompilationRule;
-import com.squareup.javapoet.CodeBlock;
-import java.util.stream.Stream;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.util.Elements;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link CodeBlocks}. */
-@RunWith(JUnit4.class)
-public final class CodeBlocksTest {
- private static final CodeBlock objectO = CodeBlock.of("$T o", Object.class);
- private static final CodeBlock stringS = CodeBlock.of("$T s", String.class);
- private static final CodeBlock intI = CodeBlock.of("$T i", int.class);
-
- @Rule public CompilationRule compilationRule = new CompilationRule();
- private Elements elements;
-
- @Before
- public void setUp() {
- this.elements = compilationRule.getElements();
- }
-
- @Test
- public void testToParametersCodeBlock() {
- assertThat(Stream.of(objectO, stringS, intI).collect(toParametersCodeBlock()))
- .isEqualTo(CodeBlock.of("$T o, $T s, $T i", Object.class, String.class, int.class));
- }
-
- @Test
- public void testToParametersCodeBlock_empty() {
- assertThat(Stream.<CodeBlock>of().collect(toParametersCodeBlock())).isEqualTo(CodeBlock.of(""));
- }
-
- @Test
- public void testToParametersCodeBlock_oneElement() {
- assertThat(Stream.of(objectO).collect(toParametersCodeBlock())).isEqualTo(objectO);
- }
-
- @Test
- public void testJavadocLinkTo() {
- ExecutableElement equals =
- elements
- .getTypeElement(Object.class.getCanonicalName())
- .getEnclosedElements()
- .stream()
- .filter(element -> element.getKind().equals(METHOD))
- .map(ExecutableElement.class::cast)
- .filter(method -> method.getSimpleName().contentEquals("equals"))
- .findFirst()
- .get();
- assertThat(javadocLinkTo(equals))
- .isEqualTo(CodeBlock.of("{@link $T#equals($T)}", Object.class, Object.class));
- }
-}
diff --git a/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java b/javatests/dagger/internal/codegen/javapoet/ExpressionTest.java
deleted file mode 100644
index acfa460..0000000
--- a/javatests/dagger/internal/codegen/javapoet/ExpressionTest.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.javapoet;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.auto.common.MoreTypes;
-import com.google.testing.compile.CompilationRule;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
-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;
-
-@RunWith(JUnit4.class)
-public class ExpressionTest {
- @Rule public CompilationRule compilationRule = new CompilationRule();
- private DaggerElements elements;
- private DaggerTypes types;
-
- interface Supertype {}
-
- interface Subtype extends Supertype {}
-
- @Before
- public void setUp() {
- elements = new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
- types = new DaggerTypes(compilationRule.getTypes(), elements);
- }
-
- @Test
- public void castTo() {
- TypeMirror subtype = type(Subtype.class);
- TypeMirror supertype = type(Supertype.class);
- Expression expression = Expression.create(subtype, "new $T() {}", subtype);
-
- Expression castTo = expression.castTo(supertype);
-
- assertThat(castTo.type()).isSameInstanceAs(supertype);
- assertThat(castTo.codeBlock().toString())
- .isEqualTo(
- "(dagger.internal.codegen.javapoet.ExpressionTest.Supertype) "
- + "new dagger.internal.codegen.javapoet.ExpressionTest.Subtype() {}");
- }
-
- @Test
- public void box() {
- PrimitiveType primitiveInt = types.getPrimitiveType(TypeKind.INT);
-
- Expression primitiveExpression = Expression.create(primitiveInt, "5");
- Expression boxedExpression = primitiveExpression.box(types);
-
- assertThat(boxedExpression.codeBlock().toString()).isEqualTo("(java.lang.Integer) 5");
- assertThat(MoreTypes.equivalence().equivalent(boxedExpression.type(), type(Integer.class)))
- .isTrue();
- }
-
- private TypeMirror type(Class<?> clazz) {
- return elements.getTypeElement(clazz).asType();
- }
-}
diff --git a/javatests/dagger/producers/BUILD b/javatests/dagger/producers/BUILD
deleted file mode 100644
index 1e1bd66..0000000
--- a/javatests/dagger/producers/BUILD
+++ /dev/null
@@ -1,41 +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 for dagger.producers
-
-package(default_visibility = ["//:src"])
-
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
- "SOURCE_7_TARGET_7",
-)
-load("//:test_defs.bzl", "GenJavaTests")
-
-GenJavaTests(
- name = "producers_tests",
- srcs = glob(["**/*.java"]),
- functional = 0,
- javacopts = SOURCE_7_TARGET_7 + DOCLINT_REFERENCES + DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//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",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
diff --git a/javatests/dagger/producers/ProducedTest.java b/javatests/dagger/producers/ProducedTest.java
deleted file mode 100644
index 5804141..0000000
--- a/javatests/dagger/producers/ProducedTest.java
+++ /dev/null
@@ -1,61 +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.producers;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.testing.EqualsTester;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link Produced}.
- */
-@RunWith(JUnit4.class)
-public class ProducedTest {
- @Test public void successfulProduced() throws ExecutionException {
- Object o = new Object();
- assertThat(Produced.successful(5).get()).isEqualTo(5);
- assertThat(Produced.successful("monkey").get()).isEqualTo("monkey");
- assertThat(Produced.successful(o).get()).isSameInstanceAs(o);
- }
-
- @Test public void failedProduced() {
- RuntimeException cause = new RuntimeException("monkey");
- try {
- Produced.failed(cause).get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isSameInstanceAs(cause);
- }
- }
-
- @Test public void producedEquivalence() {
- RuntimeException e1 = new RuntimeException("monkey");
- RuntimeException e2 = new CancellationException();
- new EqualsTester()
- .addEqualityGroup(Produced.successful(132435), Produced.successful(132435))
- .addEqualityGroup(Produced.successful("hi"), Produced.successful("hi"))
- .addEqualityGroup(Produced.failed(e1), Produced.failed(e1))
- .addEqualityGroup(Produced.failed(e2), Produced.failed(e2))
- .testEquals();
- }
-}
diff --git a/javatests/dagger/producers/internal/AbstractProducerTest.java b/javatests/dagger/producers/internal/AbstractProducerTest.java
deleted file mode 100644
index da24125..0000000
--- a/javatests/dagger/producers/internal/AbstractProducerTest.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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link AbstractProducer}.
- */
-@RunWith(JUnit4.class)
-public class AbstractProducerTest {
- @Test
- @SuppressWarnings("CheckReturnValue")
- public void get_nullPointerException() {
- Producer<Object> producer = new DelegateProducer<>(null);
- try {
- producer.get();
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- @Test public void get() throws Exception {
- Producer<Integer> producer =
- new AbstractProducer<Integer>() {
- int i = 0;
-
- @Override
- public ListenableFuture<Integer> compute() {
- return Futures.immediateFuture(i++);
- }
- };
- assertThat(producer.get().get()).isEqualTo(0);
- assertThat(producer.get().get()).isEqualTo(0);
- assertThat(producer.get().get()).isEqualTo(0);
- }
-
- static final class DelegateProducer<T> extends AbstractProducer<T> {
- private final ListenableFuture<T> delegate;
-
- DelegateProducer(ListenableFuture<T> delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public ListenableFuture<T> compute() {
- return delegate;
- }
- }
-}
diff --git a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java b/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java
deleted file mode 100644
index b29cb3c..0000000
--- a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java
+++ /dev/null
@@ -1,147 +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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
-import dagger.producers.Producer;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import javax.inject.Provider;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests {@link AbstractProducer}.
- */
-@RunWith(JUnit4.class)
-public class AbstractProducesMethodProducerTest {
- @Mock private ProductionComponentMonitor componentMonitor;
- private ProducerMonitor monitor;
- private Provider<ProductionComponentMonitor> componentMonitorProvider;
-
- @Before
- public void initMocks() {
- MockitoAnnotations.initMocks(this);
- monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
- when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
- componentMonitorProvider =
- new Provider<ProductionComponentMonitor>() {
- @Override
- public ProductionComponentMonitor get() {
- return componentMonitor;
- }
- };
- }
-
- @Test
- public void monitor_success() throws Exception {
- SettableFuture<Integer> delegateFuture = SettableFuture.create();
- Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
-
- ListenableFuture<Integer> future = producer.get();
- assertThat(future.isDone()).isFalse();
- verify(monitor).ready();
- verify(monitor).requested();
- verify(monitor).addCallbackTo(anyListenableFuture());
- verify(monitor).methodStarting();
- verify(monitor).methodFinished();
- delegateFuture.set(-42);
- assertThat(future.get()).isEqualTo(-42);
- verify(monitor).succeeded(-42);
- verifyNoMoreInteractions(monitor);
- }
-
- @Test
- public void monitor_failure() throws Exception {
- SettableFuture<Integer> delegateFuture = SettableFuture.create();
- Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
-
- ListenableFuture<Integer> future = producer.get();
- assertThat(future.isDone()).isFalse();
- verify(monitor).ready();
- verify(monitor).requested();
- verify(monitor).addCallbackTo(anyListenableFuture());
- verify(monitor).methodStarting();
- verify(monitor).methodFinished();
- Throwable t = new RuntimeException("monkey");
- delegateFuture.setException(t);
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isSameInstanceAs(t);
- }
- verify(monitor).failed(t);
- verifyNoMoreInteractions(monitor);
- }
-
- private ListenableFuture<?> anyListenableFuture() {
- return any(ListenableFuture.class);
- }
-
- @Test(expected = NullPointerException.class)
- public void monitor_null() throws Exception {
- new DelegateProducer<>(null, Futures.immediateFuture(42));
- }
-
- static final class DelegateProducer<T> extends AbstractProducesMethodProducer<Void, T> {
- private final ListenableFuture<T> delegate;
-
- DelegateProducer(
- Provider<ProductionComponentMonitor> componentMonitorProvider,
- ListenableFuture<T> delegate) {
- super(
- componentMonitorProvider,
- null, // token
- new Provider<Executor>() {
- @Override
- public Executor get() {
- return MoreExecutors.directExecutor();
- }
- });
- this.delegate = delegate;
- }
-
- @Override
- protected ListenableFuture<Void> collectDependencies() {
- return Futures.immediateFuture(null);
- }
-
- @Override
- protected ListenableFuture<T> callProducesMethod(Void asyncDependencies) {
- return delegate;
- }
- }
-}
diff --git a/javatests/dagger/producers/internal/MapOfProducerProducerTest.java b/javatests/dagger/producers/internal/MapOfProducerProducerTest.java
deleted file mode 100644
index f4be15c..0000000
--- a/javatests/dagger/producers/internal/MapOfProducerProducerTest.java
+++ /dev/null
@@ -1,67 +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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import dagger.producers.Producer;
-import dagger.producers.Producers;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class MapOfProducerProducerTest {
- @Test
- public void success() throws Exception {
- MapOfProducerProducer<Integer, String> mapOfProducerProducer =
- MapOfProducerProducer.<Integer, String>builder(2)
- .put(15, Producers.<String>immediateProducer("fifteen"))
- .put(42, Producers.<String>immediateProducer("forty two"))
- .build();
- Map<Integer, Producer<String>> map = mapOfProducerProducer.get().get();
- assertThat(map).hasSize(2);
- assertThat(map).containsKey(15);
- assertThat(map.get(15).get().get()).isEqualTo("fifteen");
- assertThat(map).containsKey(42);
- assertThat(map.get(42).get().get()).isEqualTo("forty two");
- }
-
- @Test
- public void failingContributionDoesNotFailMap() throws Exception {
- RuntimeException cause = new RuntimeException("monkey");
- MapOfProducerProducer<Integer, String> mapOfProducerProducer =
- MapOfProducerProducer.<Integer, String>builder(2)
- .put(15, Producers.<String>immediateProducer("fifteen"))
- .put(42, Producers.<String>immediateFailedProducer(cause))
- .build();
- Map<Integer, Producer<String>> map = mapOfProducerProducer.get().get();
- assertThat(map).hasSize(2);
- assertThat(map).containsKey(15);
- assertThat(map.get(15).get().get()).isEqualTo("fifteen");
- assertThat(map).containsKey(42);
- try {
- map.get(42).get().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isSameInstanceAs(cause);
- }
- }
-}
diff --git a/javatests/dagger/producers/internal/MapProducerTest.java b/javatests/dagger/producers/internal/MapProducerTest.java
deleted file mode 100644
index f74bc41..0000000
--- a/javatests/dagger/producers/internal/MapProducerTest.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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import dagger.producers.Producer;
-import dagger.producers.Producers;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class MapProducerTest {
- @Test
- public void success() throws Exception {
- Producer<Map<Integer, String>> mapProducer =
- MapProducer.<Integer, String>builder(2)
- .put(15, Producers.immediateProducer("fifteen"))
- .put(42, Producers.immediateProducer("forty two"))
- .build();
- Map<Integer, String> map = mapProducer.get().get();
- assertThat(map).hasSize(2);
- assertThat(map).containsEntry(15, "fifteen");
- assertThat(map).containsEntry(42, "forty two");
- }
-
- @Test
- public void failingContribution() throws Exception {
- RuntimeException cause = new RuntimeException("monkey");
- Producer<Map<Integer, String>> mapProducer =
- MapProducer.<Integer, String>builder(2)
- .put(15, Producers.immediateProducer("fifteen"))
- // TODO(ronshapiro): remove the type parameter when we drop java7 support
- .put(42, Producers.<String>immediateFailedProducer(cause))
- .build();
- try {
- mapProducer.get().get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isSameInstanceAs(cause);
- }
- }
-}
diff --git a/javatests/dagger/producers/internal/ProducersTest.java b/javatests/dagger/producers/internal/ProducersTest.java
deleted file mode 100644
index 1cfe121..0000000
--- a/javatests/dagger/producers/internal/ProducersTest.java
+++ /dev/null
@@ -1,143 +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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link Producers}.
- */
-@RunWith(JUnit4.class)
-public class ProducersTest {
- @Test public void createFutureProduced_success() throws Exception {
- ListenableFuture<String> future = Futures.immediateFuture("monkey");
- ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
- assertThat(producedFuture.isDone()).isTrue();
- assertThat(producedFuture.get().get()).isEqualTo("monkey");
- }
-
- @Test public void createFutureProduced_failure() throws Exception {
- ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
- ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
- assertThat(producedFuture.isDone()).isTrue();
- assertThat(getProducedException(producedFuture.get()))
- .hasCauseThat()
- .hasMessageThat()
- .isEqualTo("monkey");
- }
-
- @Test public void createFutureProduced_cancelPropagatesBackwards() throws Exception {
- ListenableFuture<String> future = SettableFuture.create();
- ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
- assertThat(producedFuture.isDone()).isFalse();
- producedFuture.cancel(false);
- assertThat(future.isCancelled()).isTrue();
- }
-
- @Test public void createFutureProduced_cancelDoesNotPropagateForwards() throws Exception {
- ListenableFuture<String> future = SettableFuture.create();
- ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
- assertThat(producedFuture.isDone()).isFalse();
- future.cancel(false);
- assertThat(producedFuture.isCancelled()).isFalse();
- assertThat(getProducedException(producedFuture.get()))
- .hasCauseThat()
- .isInstanceOf(CancellationException.class);
- }
-
- private <T> ExecutionException getProducedException(Produced<T> produced) {
- try {
- T value = produced.get();
- throw new IllegalArgumentException("produced did not throw, but returned " + value);
- } catch (ExecutionException e) {
- return e;
- }
- }
-
- @Test public void createFutureSingletonSet_success() throws Exception {
- ListenableFuture<String> future = Futures.immediateFuture("monkey");
- ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
- assertThat(setFuture.isDone()).isTrue();
- assertThat(setFuture.get()).containsExactly("monkey");
- }
-
- @Test public void createFutureSingletonSet_failure() throws Exception {
- ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
- ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
- assertThat(setFuture.isDone()).isTrue();
- try {
- setFuture.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("monkey");
- }
- }
-
- @Test
- public void allAsSet_success() throws Exception {
- ListenableFuture<Set<String>> future =
- Producers.allAsSet(
- ImmutableList.of(
- Futures.immediateFuture("monkey"), Futures.immediateFuture("gorilla")));
- assertThat(future.isDone()).isTrue();
- assertThat(future.get()).containsExactly("monkey", "gorilla");
- }
-
- @Test
- public void allAsSet_failure() throws Exception {
- ListenableFuture<Set<String>> future =
- Producers.allAsSet(
- ImmutableList.of(
- Futures.immediateFuture("monkey"),
- Futures.<String>immediateFailedFuture(new RuntimeException("gorilla"))));
- assertThat(future.isDone()).isTrue();
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("gorilla");
- }
- }
-
- @Test public void producerFromProvider_doesntCache() throws Exception {
- Producer<Integer> producer = Producers.producerFromProvider(new Provider<Integer>() {
- int i = 0;
-
- @Override public Integer get() {
- return i++;
- }
- });
- assertThat(producer.get().get()).isEqualTo(0);
- assertThat(producer.get().get()).isEqualTo(1);
- assertThat(producer.get().get()).isEqualTo(2);
- }
-}
diff --git a/javatests/dagger/producers/internal/SetOfProducedProducerTest.java b/javatests/dagger/producers/internal/SetOfProducedProducerTest.java
deleted file mode 100644
index 4dffd74..0000000
--- a/javatests/dagger/producers/internal/SetOfProducedProducerTest.java
+++ /dev/null
@@ -1,148 +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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.Producers;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link SetOfProducedProducer}.
- */
-@RunWith(JUnit4.class)
-public class SetOfProducedProducerTest {
- @Test
- public void success() throws Exception {
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(1, 1)
- .addProducer(Producers.immediateProducer(1))
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(5, 7)))
- .build();
- assertThat(producer.get().get())
- .containsExactly(
- Produced.successful(1),
- Produced.successful(5),
- Produced.successful(7));
- }
-
- @Test
- public void failure() throws Exception {
- RuntimeException e = new RuntimeException("monkey");
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(1, 1)
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)))
- .addProducer(Producers.<Integer>immediateFailedProducer(e))
- .build();
- assertThat(producer.get().get())
- .containsExactly(
- Produced.successful(1), Produced.successful(2), Produced.<Integer>failed(e));
- }
-
- @Test
- public void delegateNpe() throws Exception {
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(1, 0)
- .addProducer(Producers.<Integer>immediateProducer(null))
- .build();
- Results<Integer> results = Results.create(producer.get().get());
- assertThat(results.successes).isEmpty();
- assertThat(results.failures).hasSize(1);
- assertThat(Iterables.getOnlyElement(results.failures))
- .hasCauseThat()
- .isInstanceOf(NullPointerException.class);
- }
-
- @Test
- public void delegateSetNpe() throws Exception {
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(0, 1)
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(null))
- .build();
- Results<Integer> results = Results.create(producer.get().get());
- assertThat(results.successes).isEmpty();
- assertThat(results.failures).hasSize(1);
- assertThat(Iterables.getOnlyElement(results.failures))
- .hasCauseThat()
- .isInstanceOf(NullPointerException.class);
- }
-
- @Test
- public void delegateElementNpe() throws Exception {
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(0, 1)
- .addCollectionProducer(
- Producers.<Set<Integer>>immediateProducer(Collections.<Integer>singleton(null)))
- .build();
- Results<Integer> results = Results.create(producer.get().get());
- assertThat(results.successes).isEmpty();
- assertThat(results.failures).hasSize(1);
- assertThat(Iterables.getOnlyElement(results.failures))
- .hasCauseThat()
- .isInstanceOf(NullPointerException.class);
- }
-
- @Test
- public void oneOfDelegateElementNpe() throws Exception {
- Producer<Set<Produced<Integer>>> producer =
- SetOfProducedProducer.<Integer>builder(0, 1)
- .addCollectionProducer(
- Producers.<Set<Integer>>immediateProducer(
- Sets.newHashSet(Arrays.asList(5, 2, null))))
- .build();
- Results<Integer> results = Results.create(producer.get().get());
- assertThat(results.successes).containsExactly(2, 5);
- assertThat(results.failures).hasSize(1);
- assertThat(Iterables.getOnlyElement(results.failures))
- .hasCauseThat()
- .isInstanceOf(NullPointerException.class);
- }
-
- static final class Results<T> {
- final ImmutableSet<T> successes;
- final ImmutableSet<ExecutionException> failures;
-
- private Results(ImmutableSet<T> successes, ImmutableSet<ExecutionException> failures) {
- this.successes = successes;
- this.failures = failures;
- }
-
- static <T> Results<T> create(Set<Produced<T>> setOfProduced) {
- ImmutableSet.Builder<T> successes = ImmutableSet.builder();
- ImmutableSet.Builder<ExecutionException> failures = ImmutableSet.builder();
- for (Produced<T> produced : setOfProduced) {
- try {
- successes.add(produced.get());
- } catch (ExecutionException e) {
- failures.add(e);
- }
- }
- return new Results<T>(successes.build(), failures.build());
- }
- }
-}
diff --git a/javatests/dagger/producers/internal/SetProducerTest.java b/javatests/dagger/producers/internal/SetProducerTest.java
deleted file mode 100644
index 2bfd51a..0000000
--- a/javatests/dagger/producers/internal/SetProducerTest.java
+++ /dev/null
@@ -1,94 +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.producers.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.Producer;
-import dagger.producers.Producers;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests {@link SetProducer}.
- */
-@RunWith(JUnit4.class)
-public class SetProducerTest {
- @Test
- public void success() throws Exception {
- Producer<Set<Integer>> producer =
- SetProducer.<Integer>builder(1, 1)
- .addProducer(Producers.immediateProducer(1))
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(5, 7)))
- .build();
- assertThat(producer.get().get()).containsExactly(1, 5, 7);
- }
-
- @Test
- public void delegateNpe() throws Exception {
- Producer<Set<Integer>> producer =
- SetProducer.<Integer>builder(1, 0)
- .addProducer(Producers.<Integer>immediateProducer(null))
- .build();
- ListenableFuture<Set<Integer>> future = producer.get();
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(NullPointerException.class);
- }
- }
-
- @Test
- public void delegateSetNpe() throws Exception {
- Producer<Set<Integer>> producer =
- SetProducer.<Integer>builder(0, 1)
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(null))
- .build();
- ListenableFuture<Set<Integer>> future = producer.get();
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(NullPointerException.class);
- }
- }
-
- @Test
- public void delegateElementNpe() throws Exception {
- Producer<Set<Integer>> producer =
- SetProducer.<Integer>builder(0, 2)
- .addCollectionProducer(Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)))
- .addCollectionProducer(
- Producers.<Set<Integer>>immediateProducer(Collections.<Integer>singleton(null)))
- .build();
- ListenableFuture<Set<Integer>> future = producer.get();
- try {
- future.get();
- fail();
- } catch (ExecutionException e) {
- assertThat(e).hasCauseThat().isInstanceOf(NullPointerException.class);
- }
- }
-}
diff --git a/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java b/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java
deleted file mode 100644
index 449b5a6..0000000
--- a/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.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.producers.monitoring;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.google.common.testing.FakeTicker;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-public final class TimingProductionComponentMonitorTest {
- private static final class ProducerClassA {}
-
- private static final class ProducerClassB {}
-
- @Mock private ProductionComponentTimingRecorder.Factory productionComponentTimingRecorderFactory;
- @Mock private ProductionComponentTimingRecorder productionComponentTimingRecorder;
- @Mock private ProducerTimingRecorder producerTimingRecorderA;
- @Mock private ProducerTimingRecorder producerTimingRecorderB;
-
- private FakeTicker ticker;
- private ProductionComponentMonitor.Factory monitorFactory;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(productionComponentTimingRecorderFactory.create(any(Object.class)))
- .thenReturn(productionComponentTimingRecorder);
- when(
- productionComponentTimingRecorder.producerTimingRecorderFor(
- ProducerToken.create(ProducerClassA.class)))
- .thenReturn(producerTimingRecorderA);
- when(
- productionComponentTimingRecorder.producerTimingRecorderFor(
- ProducerToken.create(ProducerClassB.class)))
- .thenReturn(producerTimingRecorderB);
- ticker = new FakeTicker();
- monitorFactory =
- new TimingProductionComponentMonitor.Factory(
- productionComponentTimingRecorderFactory, ticker);
- }
-
- @Test
- public void normalExecution_success() {
- ProductionComponentMonitor monitor = monitorFactory.create(new Object());
- ProducerMonitor producerMonitorA =
- monitor.producerMonitorFor(ProducerToken.create(ProducerClassA.class));
- ticker.advance(5000222);
- producerMonitorA.methodStarting();
- ticker.advance(1333);
- producerMonitorA.methodFinished();
- ticker.advance(40000555);
- ProducerMonitor producerMonitorB =
- monitor.producerMonitorFor(ProducerToken.create(ProducerClassB.class));
- producerMonitorB.methodStarting();
- ticker.advance(2000777);
- producerMonitorA.succeeded(new Object());
- ticker.advance(3000999);
- producerMonitorB.methodFinished();
- ticker.advance(100000222);
- producerMonitorB.succeeded(new Object());
-
- verify(producerTimingRecorderA).recordMethod(5000222, 1333);
- verify(producerTimingRecorderA).recordSuccess(1333 + 40000555 + 2000777);
- verify(producerTimingRecorderB).recordMethod(5000222 + 1333 + 40000555, 2000777 + 3000999);
- verify(producerTimingRecorderB).recordSuccess(2000777 + 3000999 + 100000222);
- verifyNoMoreInteractions(producerTimingRecorderA, producerTimingRecorderB);
- }
-
- @Test
- public void normalExecution_failure() {
- Throwable failureA = new RuntimeException("monkey");
- Throwable failureB = new RuntimeException("gorilla");
- ProductionComponentMonitor monitor = monitorFactory.create(new Object());
- ProducerMonitor producerMonitorA =
- monitor.producerMonitorFor(ProducerToken.create(ProducerClassA.class));
- ticker.advance(5000222);
- producerMonitorA.methodStarting();
- ticker.advance(1333);
- producerMonitorA.methodFinished();
- ticker.advance(40000555);
- ProducerMonitor producerMonitorB =
- monitor.producerMonitorFor(ProducerToken.create(ProducerClassB.class));
- producerMonitorB.methodStarting();
- ticker.advance(2000777);
- producerMonitorA.failed(failureA);
- ticker.advance(3000999);
- producerMonitorB.methodFinished();
- ticker.advance(100000222);
- producerMonitorB.failed(failureB);
-
- verify(producerTimingRecorderA).recordMethod(5000222, 1333);
- verify(producerTimingRecorderA).recordFailure(failureA, 1333 + 40000555 + 2000777);
- verify(producerTimingRecorderB).recordMethod(5000222 + 1333 + 40000555, 2000777 + 3000999);
- verify(producerTimingRecorderB).recordFailure(failureB, 2000777 + 3000999 + 100000222);
- verifyNoMoreInteractions(producerTimingRecorderA, producerTimingRecorderB);
- }
-}
diff --git a/javatests/dagger/producers/monitoring/TimingRecordersTest.java b/javatests/dagger/producers/monitoring/TimingRecordersTest.java
deleted file mode 100644
index 4e5d74f..0000000
--- a/javatests/dagger/producers/monitoring/TimingRecordersTest.java
+++ /dev/null
@@ -1,361 +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.producers.monitoring;
-
-import static com.google.common.truth.Truth.assertThat;
-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;
-import static org.mockito.Mockito.when;
-
-import com.google.common.collect.ImmutableList;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-public final class TimingRecordersTest {
- @Mock
- private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactory;
-
- @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorder;
- @Mock private ProducerTimingRecorder mockProducerTimingRecorder;
-
- @Mock
- private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryA;
-
- @Mock
- private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryB;
-
- @Mock
- private ProductionComponentTimingRecorder.Factory mockProductionComponentTimingRecorderFactoryC;
-
- @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderA;
- @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderB;
- @Mock private ProductionComponentTimingRecorder mockProductionComponentTimingRecorderC;
- @Mock private ProducerTimingRecorder mockProducerTimingRecorderA;
- @Mock private ProducerTimingRecorder mockProducerTimingRecorderB;
- @Mock private ProducerTimingRecorder mockProducerTimingRecorderC;
-
- @Before
- public void initMocks() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void zeroRecordersReturnsNoOp() {
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.<ProductionComponentTimingRecorder.Factory>of());
- assertThat(factory)
- .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorderFactory());
- }
-
- @Test
- public void singleRecorder_nullProductionComponentTimingRecorder() {
- when(mockProductionComponentTimingRecorderFactory.create(any(Object.class))).thenReturn(null);
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- assertThat(factory.create(new Object()))
- .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
- }
-
- @Test
- public void singleRecorder_throwingProductionComponentTimingRecorderFactory() {
- when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- assertThat(factory.create(new Object()))
- .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
- }
-
- @Test
- public void singleRecorder_nullProducerTimingRecorder() {
- when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(null);
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- assertThat(recorder.producerTimingRecorderFor(ProducerToken.create(Object.class)))
- .isSameInstanceAs(ProducerTimingRecorder.noOp());
- }
-
- @Test
- public void singleRecorder_throwingProductionComponentTimingRecorder() {
- when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenThrow(new RuntimeException("monkey"));
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- assertThat(recorder.producerTimingRecorderFor(ProducerToken.create(Object.class)))
- .isSameInstanceAs(ProducerTimingRecorder.noOp());
- }
-
- @Test
- public void singleRecorder_normalProducerTimingRecorderSuccess() {
- setUpNormalSingleRecorder();
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order = inOrder(mockProducerTimingRecorder);
- order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorder).recordSuccess(100);
- verifyNoMoreInteractions(mockProducerTimingRecorder);
- }
-
- @Test
- public void singleRecorder_normalProducerTimingRecorderFailure() {
- setUpNormalSingleRecorder();
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
- Throwable t = new RuntimeException("monkey");
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordFailure(t, 100);
-
- InOrder order = inOrder(mockProducerTimingRecorder);
- order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorder).recordFailure(t, 100);
- verifyNoMoreInteractions(mockProducerTimingRecorder);
- }
-
- @Test
- public void singleRecorder_throwingProducerTimingRecorderSuccess() {
- setUpNormalSingleRecorder();
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerTimingRecorder)
- .recordMethod(anyLong(), anyLong());
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerTimingRecorder)
- .recordSuccess(anyLong());
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(mockProductionComponentTimingRecorderFactory));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order = inOrder(mockProducerTimingRecorder);
- order.verify(mockProducerTimingRecorder).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorder).recordSuccess(100);
- verifyNoMoreInteractions(mockProducerTimingRecorder);
- }
-
- @Test
- public void multipleRecorders_nullProductionComponentTimingRecorders() {
- when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class))).thenReturn(null);
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- assertThat(factory.create(new Object()))
- .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
- }
-
- @Test
- public void multipleRecorders_throwingProductionComponentTimingRecorderFactories() {
- when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- assertThat(factory.create(new Object()))
- .isSameInstanceAs(TimingRecorders.noOpProductionComponentTimingRecorder());
- }
-
- @Test
- public void multipleRecorders_someNullProductionComponentTimingRecorders() {
- when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorderA);
- when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(mockProducerTimingRecorderA);
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
-
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order = inOrder(mockProducerTimingRecorderA);
- order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderA).recordSuccess(100);
- verifyNoMoreInteractions(mockProducerTimingRecorderA);
- }
-
- @Test
- public void multipleRecorders_someThrowingProductionComponentTimingRecorderFactories() {
- when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorderA);
- when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
- .thenThrow(new RuntimeException("monkey"));
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(mockProducerTimingRecorderA);
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
-
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order = inOrder(mockProducerTimingRecorderA);
- order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderA).recordSuccess(100);
- verifyNoMoreInteractions(mockProducerTimingRecorderA);
- }
-
- @Test
- public void multipleRecorders_normalProductionComponentTimingRecorderSuccess() {
- setUpNormalMultipleRecorders();
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
-
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order =
- inOrder(
- mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
- order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderB).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderC).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderA).recordSuccess(100);
- order.verify(mockProducerTimingRecorderB).recordSuccess(100);
- order.verify(mockProducerTimingRecorderC).recordSuccess(100);
- verifyNoMoreInteractions(
- mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
- }
-
- @Test
- public void multipleRecorders_someThrowingProducerTimingRecordersSuccess() {
- setUpNormalMultipleRecorders();
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerTimingRecorderA)
- .recordMethod(anyLong(), anyLong());
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerTimingRecorderB)
- .recordSuccess(anyLong());
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerTimingRecorderC)
- .recordMethod(anyLong(), anyLong());
- ProductionComponentTimingRecorder.Factory factory =
- TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
- ImmutableList.of(
- mockProductionComponentTimingRecorderFactoryA,
- mockProductionComponentTimingRecorderFactoryB,
- mockProductionComponentTimingRecorderFactoryC));
- ProductionComponentTimingRecorder recorder = factory.create(new Object());
- ProducerTimingRecorder producerTimingRecorder =
- recorder.producerTimingRecorderFor(ProducerToken.create(Object.class));
-
- producerTimingRecorder.recordMethod(15, 42);
- producerTimingRecorder.recordSuccess(100);
-
- InOrder order =
- inOrder(
- mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
- order.verify(mockProducerTimingRecorderA).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderB).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderC).recordMethod(15, 42);
- order.verify(mockProducerTimingRecorderA).recordSuccess(100);
- order.verify(mockProducerTimingRecorderB).recordSuccess(100);
- order.verify(mockProducerTimingRecorderC).recordSuccess(100);
- verifyNoMoreInteractions(
- mockProducerTimingRecorderA, mockProducerTimingRecorderB, mockProducerTimingRecorderC);
- }
-
- private void setUpNormalSingleRecorder() {
- when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(mockProducerTimingRecorder);
- }
-
- private void setUpNormalMultipleRecorders() {
- when(mockProductionComponentTimingRecorderFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorderA);
- when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorderB);
- when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
- .thenReturn(mockProductionComponentTimingRecorderC);
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(mockProducerTimingRecorderA);
- when(mockProductionComponentTimingRecorderB.producerTimingRecorderFor(any(ProducerToken.class)))
- .thenReturn(mockProducerTimingRecorderB);
- 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
deleted file mode 100644
index 47ccccb..0000000
--- a/javatests/dagger/producers/monitoring/internal/MonitorsTest.java
+++ /dev/null
@@ -1,486 +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.producers.monitoring.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import com.google.common.collect.ImmutableList;
-import dagger.producers.monitoring.ProducerMonitor;
-import dagger.producers.monitoring.ProducerToken;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(JUnit4.class)
-public final class MonitorsTest {
- @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactory;
- @Mock private ProductionComponentMonitor mockProductionComponentMonitor;
- @Mock private ProducerMonitor mockProducerMonitor;
- @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryA;
- @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryB;
- @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryC;
- @Mock private ProductionComponentMonitor mockProductionComponentMonitorA;
- @Mock private ProductionComponentMonitor mockProductionComponentMonitorB;
- @Mock private ProductionComponentMonitor mockProductionComponentMonitorC;
- @Mock private ProducerMonitor mockProducerMonitorA;
- @Mock private ProducerMonitor mockProducerMonitorB;
- @Mock private ProducerMonitor mockProducerMonitorC;
-
- @Before
- public void initMocks() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void zeroMonitorsReturnsNoOp() {
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.<ProductionComponentMonitor.Factory>of());
- assertThat(factory).isSameInstanceAs(ProductionComponentMonitor.Factory.noOp());
- }
-
- @Test
- public void singleMonitor_nullProductionComponentMonitor() {
- when(mockProductionComponentMonitorFactory.create(any(Object.class))).thenReturn(null);
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- assertThat(factory.create(new Object())).isSameInstanceAs(ProductionComponentMonitor.noOp());
- }
-
- @Test
- public void singleMonitor_throwingProductionComponentMonitorFactory() {
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactory)
- .create(any(Object.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- assertThat(factory.create(new Object())).isSameInstanceAs(ProductionComponentMonitor.noOp());
- }
-
- @Test
- public void singleMonitor_nullProducerMonitor() {
- when(mockProductionComponentMonitorFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitor);
- when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(null);
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- assertThat(monitor.producerMonitorFor(ProducerToken.create(Object.class)))
- .isSameInstanceAs(ProducerMonitor.noOp());
- }
-
- @Test
- public void singleMonitor_throwingProductionComponentMonitor() {
- when(mockProductionComponentMonitorFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitor);
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitor)
- .producerMonitorFor(any(ProducerToken.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- assertThat(monitor.producerMonitorFor(ProducerToken.create(Object.class)))
- .isSameInstanceAs(ProducerMonitor.noOp());
- }
-
- @Test
- public void singleMonitor_normalProducerMonitorSuccess() {
- setUpNormalSingleMonitor();
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitor);
- order.verify(mockProducerMonitor).requested();
- order.verify(mockProducerMonitor).methodStarting();
- order.verify(mockProducerMonitor).methodFinished();
- order.verify(mockProducerMonitor).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitor);
- }
-
- @Test
- public void singleMonitor_normalProducerMonitorFailure() {
- setUpNormalSingleMonitor();
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
- Throwable t = new RuntimeException("monkey");
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.failed(t);
-
- InOrder order = inOrder(mockProducerMonitor);
- order.verify(mockProducerMonitor).requested();
- order.verify(mockProducerMonitor).methodStarting();
- order.verify(mockProducerMonitor).methodFinished();
- order.verify(mockProducerMonitor).failed(t);
- verifyNoMoreInteractions(mockProducerMonitor);
- }
-
- @Test
- public void singleMonitor_throwingProducerMonitorSuccess() {
- setUpNormalSingleMonitor();
- 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(any(Object.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitor);
- order.verify(mockProducerMonitor).requested();
- order.verify(mockProducerMonitor).methodStarting();
- order.verify(mockProducerMonitor).methodFinished();
- order.verify(mockProducerMonitor).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitor);
- }
-
- @Test
- public void singleMonitor_throwingProducerMonitorFailure() {
- setUpNormalSingleMonitor();
- 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).failed(any(Throwable.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(mockProductionComponentMonitorFactory));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
- Throwable t = new RuntimeException("gorilla");
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.failed(t);
-
- InOrder order = inOrder(mockProducerMonitor);
- order.verify(mockProducerMonitor).requested();
- order.verify(mockProducerMonitor).methodStarting();
- order.verify(mockProducerMonitor).methodFinished();
- order.verify(mockProducerMonitor).failed(t);
- verifyNoMoreInteractions(mockProducerMonitor);
- }
-
- @Test
- public void multipleMonitors_nullProductionComponentMonitors() {
- when(mockProductionComponentMonitorFactoryA.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentMonitorFactoryB.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentMonitorFactoryC.create(any(Object.class))).thenReturn(null);
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- assertThat(factory.create(new Object())).isSameInstanceAs(ProductionComponentMonitor.noOp());
- }
-
- @Test
- public void multipleMonitors_throwingProductionComponentMonitorFactories() {
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactoryA)
- .create(any(Object.class));
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactoryB)
- .create(any(Object.class));
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactoryC)
- .create(any(Object.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- assertThat(factory.create(new Object())).isSameInstanceAs(ProductionComponentMonitor.noOp());
- }
-
- @Test
- public void multipleMonitors_someNullProductionComponentMonitors() {
- when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitorA);
- when(mockProductionComponentMonitorFactoryB.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentMonitorFactoryC.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitorA);
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitorA);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorA).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitorA);
- }
-
- @Test
- public void multipleMonitors_someThrowingProductionComponentMonitorFactories() {
- when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitorA);
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactoryB)
- .create(any(Object.class));
- doThrow(new RuntimeException("monkey"))
- .when(mockProductionComponentMonitorFactoryC)
- .create(any(Object.class));
- when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitorA);
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitorA);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorA).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitorA);
- }
-
- @Test
- public void multipleMonitors_normalProductionComponentMonitorSuccess() {
- setUpNormalMultipleMonitors();
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorB).requested();
- order.verify(mockProducerMonitorC).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorB).methodStarting();
- order.verify(mockProducerMonitorC).methodStarting();
- order.verify(mockProducerMonitorC).methodFinished();
- order.verify(mockProducerMonitorB).methodFinished();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorC).succeeded(o);
- order.verify(mockProducerMonitorB).succeeded(o);
- order.verify(mockProducerMonitorA).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- }
-
- @Test
- public void multipleMonitors_normalProductionComponentMonitorFailure() {
- setUpNormalMultipleMonitors();
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Throwable t = new RuntimeException("chimpanzee");
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.failed(t);
-
- InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorB).requested();
- order.verify(mockProducerMonitorC).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorB).methodStarting();
- order.verify(mockProducerMonitorC).methodStarting();
- order.verify(mockProducerMonitorC).methodFinished();
- order.verify(mockProducerMonitorB).methodFinished();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorC).failed(t);
- order.verify(mockProducerMonitorB).failed(t);
- order.verify(mockProducerMonitorA).failed(t);
- verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- }
-
- @Test
- public void multipleMonitors_someThrowingProducerMonitorsSuccess() {
- setUpNormalMultipleMonitors();
- 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(any(Object.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Object o = new Object();
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.succeeded(o);
-
- InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorB).requested();
- order.verify(mockProducerMonitorC).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorB).methodStarting();
- order.verify(mockProducerMonitorC).methodStarting();
- order.verify(mockProducerMonitorC).methodFinished();
- order.verify(mockProducerMonitorB).methodFinished();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorC).succeeded(o);
- order.verify(mockProducerMonitorB).succeeded(o);
- order.verify(mockProducerMonitorA).succeeded(o);
- verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- }
-
- @Test
- public void multipleMonitors_someThrowingProducerMonitorsFailure() {
- setUpNormalMultipleMonitors();
- 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).failed(any(Throwable.class));
- ProductionComponentMonitor.Factory factory =
- Monitors.delegatingProductionComponentMonitorFactory(
- ImmutableList.of(
- mockProductionComponentMonitorFactoryA,
- mockProductionComponentMonitorFactoryB,
- mockProductionComponentMonitorFactoryC));
- ProductionComponentMonitor monitor = factory.create(new Object());
- ProducerMonitor producerMonitor =
- monitor.producerMonitorFor(ProducerToken.create(Object.class));
-
- Throwable t = new RuntimeException("chimpanzee");
- producerMonitor.requested();
- producerMonitor.methodStarting();
- producerMonitor.methodFinished();
- producerMonitor.failed(t);
-
- InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- order.verify(mockProducerMonitorA).requested();
- order.verify(mockProducerMonitorB).requested();
- order.verify(mockProducerMonitorC).requested();
- order.verify(mockProducerMonitorA).methodStarting();
- order.verify(mockProducerMonitorB).methodStarting();
- order.verify(mockProducerMonitorC).methodStarting();
- order.verify(mockProducerMonitorC).methodFinished();
- order.verify(mockProducerMonitorB).methodFinished();
- order.verify(mockProducerMonitorA).methodFinished();
- order.verify(mockProducerMonitorC).failed(t);
- order.verify(mockProducerMonitorB).failed(t);
- order.verify(mockProducerMonitorA).failed(t);
- verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
- }
-
- private void setUpNormalSingleMonitor() {
- when(mockProductionComponentMonitorFactory.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitor);
- when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitor);
- }
-
- private void setUpNormalMultipleMonitors() {
- when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitorA);
- when(mockProductionComponentMonitorFactoryB.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitorB);
- when(mockProductionComponentMonitorFactoryC.create(any(Object.class)))
- .thenReturn(mockProductionComponentMonitorC);
- when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitorA);
- when(mockProductionComponentMonitorB.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitorB);
- when(mockProductionComponentMonitorC.producerMonitorFor(any(ProducerToken.class)))
- .thenReturn(mockProducerMonitorC);
- }
-}
diff --git a/javatests/dagger/spi/BUILD b/javatests/dagger/spi/BUILD
deleted file mode 100644
index a94461b..0000000
--- a/javatests/dagger/spi/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:
-# Tests for the Dagger SPI
-
-package(default_visibility = ["//:src"])
-
-load("//:test_defs.bzl", "GenJavaTests")
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
-
-GenJavaTests(
- name = "spi_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen:processor",
- "//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
deleted file mode 100644
index 8fd0e35..0000000
--- a/javatests/dagger/spi/FailingPlugin.java
+++ /dev/null
@@ -1,93 +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.spi;
-
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph;
-import java.util.Map;
-import java.util.Set;
-
-@AutoService(BindingGraphPlugin.class)
-public final class FailingPlugin implements BindingGraphPlugin {
- private Map<String, String> options;
-
- @Override
- public Set<String> supportedOptions() {
- return ImmutableSet.of(
- "error_on_binding",
- "error_on_dependency",
- "error_on_component",
- "error_on_subcomponents");
- }
-
- @Override
- public void initOptions(Map<String, String> options) {
- this.options = options;
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- if (options.containsKey("error_on_binding")) {
- String key = options.get("error_on_binding");
- bindingGraph.bindings().stream()
- .filter(binding -> binding.key().toString().equals(key))
- .forEach(
- binding ->
- diagnosticReporter.reportBinding(ERROR, binding, "Bad Binding: %s", binding));
- }
-
- if (options.containsKey("error_on_component")) {
- diagnosticReporter.reportComponent(
- ERROR,
- bindingGraph.rootComponentNode(),
- "Bad Component: %s",
- bindingGraph.rootComponentNode());
- }
-
- if (options.containsKey("error_on_subcomponents")) {
- bindingGraph.componentNodes().stream()
- .filter(componentNode -> !componentNode.componentPath().atRoot())
- .forEach(
- componentNode ->
- diagnosticReporter.reportComponent(
- ERROR, componentNode, "Bad Subcomponent: %s", componentNode));
- }
-
- if (options.containsKey("error_on_dependency")) {
- String dependency = options.get("error_on_dependency");
- bindingGraph.dependencyEdges().stream()
- .filter(
- edge ->
- edge.dependencyRequest()
- .requestElement()
- .get()
- .getSimpleName()
- .contentEquals(dependency))
- .forEach(
- edge -> diagnosticReporter.reportDependency(ERROR, edge, "Bad Dependency: %s", edge));
- }
-
- }
-
- @Override
- public String pluginName() {
- return "FailingPlugin";
- }
-}
diff --git a/javatests/dagger/spi/SpiPluginTest.java b/javatests/dagger/spi/SpiPluginTest.java
deleted file mode 100644
index 613a915..0000000
--- a/javatests/dagger/spi/SpiPluginTest.java
+++ /dev/null
@@ -1,506 +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.spi;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.ComponentProcessor;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class SpiPluginTest {
- @Test
- public void moduleBinding() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface TestModule {",
- " @Provides",
- " static int provideInt() {",
- " return 0;",
- " }",
- "}");
-
- Compilation compilation =
- javac()
- .withProcessors(new ComponentProcessor())
- .withOptions(
- "-Aerror_on_binding=java.lang.Integer", "-Adagger.fullBindingGraphValidation=ERROR")
- .compile(module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message("[FailingPlugin] Bad Binding: @Provides int test.TestModule.provideInt()"))
- .inFile(module)
- .onLineContaining("interface TestModule");
- }
-
- @Test
- public void dependencyTraceAtBinding() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " Foo foo();",
- "}");
-
- Compilation compilation =
- javac()
- .withProcessors(new ComponentProcessor())
- .withOptions("-Aerror_on_binding=test.Foo")
- .compile(component, foo);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Binding: @Inject test.Foo()",
- " test.Foo is provided at",
- " test.TestComponent.foo()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void dependencyTraceAtDependencyRequest() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Duplicated inFooDep) {}",
- "}");
- JavaFileObject duplicated =
- JavaFileObjects.forSourceLines(
- "test.Duplicated",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Duplicated {",
- " @Inject Duplicated() {}",
- "}");
- JavaFileObject entryPoint =
- JavaFileObjects.forSourceLines(
- "test.EntryPoint",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class EntryPoint {",
- " @Inject EntryPoint(Foo foo, Duplicated dup1, Duplicated dup2) {}",
- "}");
- JavaFileObject chain1 =
- JavaFileObjects.forSourceLines(
- "test.Chain1",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain1 {",
- " @Inject Chain1(Chain2 chain) {}",
- "}");
- JavaFileObject chain2 =
- JavaFileObjects.forSourceLines(
- "test.Chain2",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain2 {",
- " @Inject Chain2(Chain3 chain) {}",
- "}");
- JavaFileObject chain3 =
- JavaFileObjects.forSourceLines(
- "test.Chain3",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain3 {",
- " @Inject Chain3(Foo foo) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " EntryPoint entryPoint();",
- " Chain1 chain();",
- "}");
-
- CompilationFactory compilationFactory =
- new CompilationFactory(component, foo, duplicated, entryPoint, chain1, chain2, chain3);
-
- assertThat(compilationFactory.compilationWithErrorOnDependency("entryPoint"))
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Dependency: test.TestComponent.entryPoint() (entry point)",
- " test.EntryPoint is provided at",
- " test.TestComponent.entryPoint()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- assertThat(compilationFactory.compilationWithErrorOnDependency("dup1"))
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup1, …)",
- " test.Duplicated is injected at",
- " test.EntryPoint(…, dup1, …)",
- " test.EntryPoint is provided at",
- " test.TestComponent.entryPoint()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- assertThat(compilationFactory.compilationWithErrorOnDependency("dup2"))
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup2)",
- " test.Duplicated is injected at",
- " test.EntryPoint(…, dup2)",
- " test.EntryPoint is provided at",
- " test.TestComponent.entryPoint()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
-
- Compilation inFooDepCompilation =
- compilationFactory.compilationWithErrorOnDependency("inFooDep");
- assertThat(inFooDepCompilation)
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Dependency: test.Foo(inFooDep)",
- " test.Duplicated is injected at",
- " test.Foo(inFooDep)",
- " test.Foo is injected at",
- " test.EntryPoint(foo, …)",
- " test.EntryPoint is provided at",
- " test.TestComponent.entryPoint()",
- "The following other entry points also depend on it:",
- " test.TestComponent.chain()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void dependencyTraceAtDependencyRequest_subcomponents() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo() {}",
- "}");
- JavaFileObject entryPoint =
- JavaFileObjects.forSourceLines(
- "test.EntryPoint",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class EntryPoint {",
- " @Inject EntryPoint(Foo foo) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " TestSubcomponent sub();",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface TestSubcomponent {",
- " EntryPoint childEntryPoint();",
- "}");
-
- CompilationFactory compilationFactory =
- new CompilationFactory(component, subcomponent, foo, entryPoint);
- assertThat(compilationFactory.compilationWithErrorOnDependency("childEntryPoint"))
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Dependency: "
- + "test.TestSubcomponent.childEntryPoint() (entry point)",
- " test.EntryPoint is provided at",
- " test.TestSubcomponent.childEntryPoint()"
- + " [test.TestComponent → test.TestSubcomponent]"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- assertThat(compilationFactory.compilationWithErrorOnDependency("foo"))
- .hadErrorContaining(
- // TODO(ronshapiro): Maybe make the component path resemble a stack trace:
- // test.TestSubcomponent is a child of
- // test.TestComponent
- // TODO(dpb): Or invert the order: Child → Parent
- message(
- "[FailingPlugin] Bad Dependency: test.EntryPoint(foo)",
- " test.Foo is injected at",
- " test.EntryPoint(foo)",
- " test.EntryPoint is provided at",
- " test.TestSubcomponent.childEntryPoint() "
- + "[test.TestComponent → test.TestSubcomponent]"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void errorOnComponent() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {}");
-
- Compilation compilation =
- javac()
- .withProcessors(new ComponentProcessor())
- .withOptions("-Aerror_on_component")
- .compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("[FailingPlugin] Bad Component: test.TestComponent")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
- public void errorOnSubcomponent() {
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface TestSubcomponent {}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " TestSubcomponent subcomponent();",
- "}");
-
- Compilation compilation =
- javac()
- .withProcessors(new ComponentProcessor())
- .withOptions("-Aerror_on_subcomponents")
- .compile(component, subcomponent);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "[FailingPlugin] Bad Subcomponent: test.TestComponent → test.TestSubcomponent "
- + "[test.TestComponent → test.TestSubcomponent]")
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- // SpiDiagnosticReporter uses a shortest path algorithm to determine a dependency trace to a
- // binding. Without modifications, this would produce a strange error if a shorter path exists
- // from one entrypoint, through a @Module.subcomponents builder binding edge, and to the binding
- // usage within the subcomponent. Therefore, when scanning for the shortest path, we only consider
- // BindingNodes so we don't cross component boundaries. This test exhibits this case.
- @Test
- public void shortestPathToBindingExistsThroughSubcomponentBuilder() {
- JavaFileObject chain1 =
- JavaFileObjects.forSourceLines(
- "test.Chain1",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain1 {",
- " @Inject Chain1(Chain2 chain) {}",
- "}");
- JavaFileObject chain2 =
- JavaFileObjects.forSourceLines(
- "test.Chain2",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain2 {",
- " @Inject Chain2(Chain3 chain) {}",
- "}");
- JavaFileObject chain3 =
- JavaFileObjects.forSourceLines(
- "test.Chain3",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Chain3 {",
- " @Inject Chain3(ExposedOnSubcomponent exposedOnSubcomponent) {}",
- "}");
- JavaFileObject exposedOnSubcomponent =
- JavaFileObjects.forSourceLines(
- "test.ExposedOnSubcomponent",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class ExposedOnSubcomponent {",
- " @Inject ExposedOnSubcomponent() {}",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.TestSubcomponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface TestSubcomponent {",
- " ExposedOnSubcomponent exposedOnSubcomponent();",
- "",
- " @Subcomponent.Builder",
- " interface Builder {",
- " TestSubcomponent build();",
- " }",
- "}");
- JavaFileObject subcomponentModule =
- JavaFileObjects.forSourceLines(
- "test.SubcomponentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "",
- "@Module(subcomponents = TestSubcomponent.class)",
- "interface SubcomponentModule {}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component(modules = SubcomponentModule.class)",
- "interface TestComponent {",
- " Chain1 chain();",
- " TestSubcomponent.Builder subcomponent();",
- "}");
-
- Compilation compilation =
- javac()
- .withProcessors(new ComponentProcessor())
- .withOptions("-Aerror_on_binding=test.ExposedOnSubcomponent")
- .compile(
- component,
- subcomponent,
- chain1,
- chain2,
- chain3,
- exposedOnSubcomponent,
- subcomponentModule);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "[FailingPlugin] Bad Binding: @Inject test.ExposedOnSubcomponent()",
- " test.ExposedOnSubcomponent is injected at",
- " test.Chain3(exposedOnSubcomponent)",
- " test.Chain3 is injected at",
- " test.Chain2(chain)",
- " test.Chain2 is injected at",
- " test.Chain1(chain)",
- " test.Chain1 is provided at",
- " test.TestComponent.chain()",
- "The following other entry points also depend on it:",
- " test.TestSubcomponent.exposedOnSubcomponent() "
- + "[test.TestComponent → test.TestSubcomponent]"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- // This works around an issue in the opensource compile testing where only one diagnostic is
- // recorded per line. When multiple validation items resolve to the same entry point, we can
- // only see the first. This helper class makes it easier to compile all of the files in the test
- // multiple times with different options to single out each error
- private static class CompilationFactory {
- private final ImmutableList<JavaFileObject> javaFileObjects;
-
- CompilationFactory(JavaFileObject... javaFileObjects) {
- this.javaFileObjects = ImmutableList.copyOf(javaFileObjects);
- }
-
- private Compilation compilationWithErrorOnDependency(String dependencySimpleName) {
- return javac()
- .withProcessors(new ComponentProcessor())
- .withOptions("-Aerror_on_dependency=" + dependencySimpleName)
- .compile(javaFileObjects);
- }
- }
-
- private static String message(String... lines) {
- return Joiner.on("\n ").join(lines);
- }
-}
diff --git a/lib/auto-common-0.10-sources.jar b/lib/auto-common-0.10-sources.jar
deleted file mode 100644
index 59bf056..0000000
--- a/lib/auto-common-0.10-sources.jar
+++ /dev/null
Binary files differ
diff --git a/lib/auto-common-0.10-sources.jar.asc b/lib/auto-common-0.10-sources.jar.asc
deleted file mode 100644
index ecc3339..0000000
--- a/lib/auto-common-0.10-sources.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index b9b3bee..0000000
--- a/lib/auto-common-0.10-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-913c8de9604380c6e135086132adb26c77fa6c53
\ No newline at end of file
diff --git a/lib/auto-common-0.10.jar b/lib/auto-common-0.10.jar
deleted file mode 100644
index 8cbfa72..0000000
--- a/lib/auto-common-0.10.jar
+++ /dev/null
Binary files differ
diff --git a/lib/auto-common-0.10.jar.asc b/lib/auto-common-0.10.jar.asc
deleted file mode 100644
index 6d81bdf..0000000
--- a/lib/auto-common-0.10.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 2056a80..0000000
--- a/lib/auto-common-0.10.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c8f153ebe04a17183480ab4016098055fb474364
\ No newline at end of file
diff --git a/lib/auto-common-1.0-20151022.071545-39-sources.jar b/lib/auto-common-1.0-20151022.071545-39-sources.jar
new file mode 100644
index 0000000..66b78b0
--- /dev/null
+++ b/lib/auto-common-1.0-20151022.071545-39-sources.jar
Binary files differ
diff --git a/lib/auto-common-1.0-20151022.071545-39.jar b/lib/auto-common-1.0-20151022.071545-39.jar
new file mode 100644
index 0000000..8967dea
--- /dev/null
+++ b/lib/auto-common-1.0-20151022.071545-39.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/auto-common-1.0-20151022.071545-39.jar.txt
similarity index 100%
rename from lib/NOTICE
rename to lib/auto-common-1.0-20151022.071545-39.jar.txt
diff --git a/lib/auto-factory-1.0-20150915.183854-35-sources.jar b/lib/auto-factory-1.0-20150915.183854-35-sources.jar
new file mode 100644
index 0000000..5c12407
--- /dev/null
+++ b/lib/auto-factory-1.0-20150915.183854-35-sources.jar
Binary files differ
diff --git a/lib/auto-factory-1.0-20150915.183854-35.jar b/lib/auto-factory-1.0-20150915.183854-35.jar
new file mode 100644
index 0000000..09f408b
--- /dev/null
+++ b/lib/auto-factory-1.0-20150915.183854-35.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/auto-factory-1.0-20150915.183854-35.jar.txt
similarity index 100%
copy from lib/NOTICE
copy to lib/auto-factory-1.0-20150915.183854-35.jar.txt
diff --git a/lib/auto-factory-1.0-beta6-sources.jar b/lib/auto-factory-1.0-beta6-sources.jar
deleted file mode 100644
index 56c6909..0000000
--- a/lib/auto-factory-1.0-beta6-sources.jar
+++ /dev/null
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
deleted file mode 100644
index be05c6e..0000000
--- a/lib/auto-factory-1.0-beta6-sources.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 9b5c0a8..0000000
--- a/lib/auto-factory-1.0-beta6-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index e47130f..0000000
--- a/lib/auto-factory-1.0-beta6.jar
+++ /dev/null
Binary files differ
diff --git a/lib/auto-factory-1.0-beta6.jar.asc b/lib/auto-factory-1.0-beta6.jar.asc
deleted file mode 100644
index 5da4253..0000000
--- a/lib/auto-factory-1.0-beta6.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 57a5e61..0000000
--- a/lib/auto-factory-1.0-beta6.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-58c804763a4d80c0884ac8a740fcff4d61da72bc
\ No newline at end of file
diff --git a/lib/auto-service-1.0-rc2-sources.jar b/lib/auto-service-1.0-rc2-sources.jar
new file mode 100644
index 0000000..cd8f687
--- /dev/null
+++ b/lib/auto-service-1.0-rc2-sources.jar
Binary files differ
diff --git a/lib/auto-service-1.0-rc2.jar b/lib/auto-service-1.0-rc2.jar
new file mode 100644
index 0000000..ea8fb68
--- /dev/null
+++ b/lib/auto-service-1.0-rc2.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/auto-service-1.0-rc2.jar.txt
similarity index 100%
copy from lib/NOTICE
copy to lib/auto-service-1.0-rc2.jar.txt
diff --git a/lib/auto-service-1.0-rc5-sources.jar b/lib/auto-service-1.0-rc5-sources.jar
deleted file mode 100644
index 8a05c9d..0000000
--- a/lib/auto-service-1.0-rc5-sources.jar
+++ /dev/null
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
deleted file mode 100644
index 08ea732..0000000
--- a/lib/auto-service-1.0-rc5-sources.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 3638b53..0000000
--- a/lib/auto-service-1.0-rc5-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index 8c43e8f..0000000
--- a/lib/auto-service-1.0-rc5.jar
+++ /dev/null
Binary files differ
diff --git a/lib/auto-service-1.0-rc5.jar.2 b/lib/auto-service-1.0-rc5.jar.2
deleted file mode 100644
index 8c43e8f..0000000
--- a/lib/auto-service-1.0-rc5.jar.2
+++ /dev/null
Binary files differ
diff --git a/lib/auto-service-1.0-rc5.jar.asc b/lib/auto-service-1.0-rc5.jar.asc
deleted file mode 100644
index e1d0163..0000000
--- a/lib/auto-service-1.0-rc5.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 2edbbf4..0000000
--- a/lib/auto-service-1.0-rc5.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index 72fd4a9..0000000
--- a/lib/auto-service-annotations-1.0-rc5-sources.jar
+++ /dev/null
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
deleted file mode 100644
index 0058623..0000000
--- a/lib/auto-service-annotations-1.0-rc5-sources.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index fc01aa3..0000000
--- a/lib/auto-service-annotations-1.0-rc5-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index fbc08ab..0000000
--- a/lib/auto-service-annotations-1.0-rc5.jar
+++ /dev/null
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
deleted file mode 100644
index b7e43ce..0000000
--- a/lib/auto-service-annotations-1.0-rc5.jar.asc
+++ /dev/null
@@ -1,11 +0,0 @@
------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
deleted file mode 100644
index 4c48b47..0000000
--- a/lib/auto-service-annotations-1.0-rc5.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6ea999af2b6262a7179a09c51a3d54e7b40a3833
\ No newline at end of file
diff --git a/lib/auto-value-1.4.1-sources.jar b/lib/auto-value-1.4.1-sources.jar
new file mode 100644
index 0000000..c6b307f
--- /dev/null
+++ b/lib/auto-value-1.4.1-sources.jar
Binary files differ
diff --git a/lib/auto-value-1.4.1.jar b/lib/auto-value-1.4.1.jar
new file mode 100644
index 0000000..eeeac6a
--- /dev/null
+++ b/lib/auto-value-1.4.1.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/auto-value-1.4.1.jar.txt
similarity index 100%
copy from lib/NOTICE
copy to lib/auto-value-1.4.1.jar.txt
diff --git a/lib/auto-value-1.6.5-sources.jar b/lib/auto-value-1.6.5-sources.jar
deleted file mode 100644
index 7d08fa7..0000000
--- a/lib/auto-value-1.6.5-sources.jar
+++ /dev/null
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
deleted file mode 100644
index 36551c1..0000000
--- a/lib/auto-value-1.6.5-sources.jar.asc
+++ /dev/null
@@ -1,12 +0,0 @@
------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
deleted file mode 100644
index ca18ea4..0000000
--- a/lib/auto-value-1.6.5-sources.jar.md5
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index 17f16a8..0000000
--- a/lib/auto-value-1.6.5-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index be17cd1..0000000
--- a/lib/auto-value-1.6.5.jar
+++ /dev/null
Binary files differ
diff --git a/lib/auto-value-1.6.5.jar.asc b/lib/auto-value-1.6.5.jar.asc
deleted file mode 100644
index f0cdc39..0000000
--- a/lib/auto-value-1.6.5.jar.asc
+++ /dev/null
@@ -1,12 +0,0 @@
------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
deleted file mode 100644
index 11a5e9d..0000000
--- a/lib/auto-value-1.6.5.jar.md5
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index edf62d8..0000000
--- a/lib/auto-value-1.6.5.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index b1a8b08..0000000
--- a/lib/auto-value-annotations-1.6.5-sources.jar
+++ /dev/null
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
deleted file mode 100644
index 81a4515..0000000
--- a/lib/auto-value-annotations-1.6.5-sources.jar.asc
+++ /dev/null
@@ -1,12 +0,0 @@
------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
deleted file mode 100644
index 897752c..0000000
--- a/lib/auto-value-annotations-1.6.5-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index f68a013..0000000
--- a/lib/auto-value-annotations-1.6.5.jar
+++ /dev/null
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
deleted file mode 100644
index 1356995..0000000
--- a/lib/auto-value-annotations-1.6.5.jar.asc
+++ /dev/null
@@ -1,12 +0,0 @@
------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
deleted file mode 100644
index 858c96e..0000000
--- a/lib/auto-value-annotations-1.6.5.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c3dad10377f0e2242c9a4b88e9704eaf79103679
\ No newline at end of file
diff --git a/lib/google-java-format-0.1-20151017.042846-2.jar b/lib/google-java-format-0.1-20151017.042846-2.jar
new file mode 100644
index 0000000..964760f
--- /dev/null
+++ b/lib/google-java-format-0.1-20151017.042846-2.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/google-java-format-0.1-20151017.042846-2.jar.txt
similarity index 100%
copy from lib/NOTICE
copy to lib/google-java-format-0.1-20151017.042846-2.jar.txt
diff --git a/lib/google-java-format-1.7-all-deps.jar b/lib/google-java-format-1.7-all-deps.jar
deleted file mode 100644
index e2d40de..0000000
--- a/lib/google-java-format-1.7-all-deps.jar
+++ /dev/null
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
deleted file mode 100644
index 73ae0e2..0000000
--- a/lib/google-java-format-1.7-all-deps.jar.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------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
deleted file mode 100644
index b247a7c..0000000
--- a/lib/google-java-format-1.7-all-deps.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index 70fca1b..0000000
--- a/lib/google-java-format-1.7-sources.jar
+++ /dev/null
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
deleted file mode 100644
index 713333c..0000000
--- a/lib/google-java-format-1.7-sources.jar.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------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
deleted file mode 100644
index 31d6337..0000000
--- a/lib/google-java-format-1.7-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index 953541c..0000000
--- a/lib/google-java-format-1.7.jar
+++ /dev/null
Binary files differ
diff --git a/lib/google-java-format-1.7.jar.asc b/lib/google-java-format-1.7.jar.asc
deleted file mode 100644
index 3642d69..0000000
--- a/lib/google-java-format-1.7.jar.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------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
deleted file mode 100644
index d0a76c2..0000000
--- a/lib/google-java-format-1.7.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-97cb6afc835d65682edc248e19170a8e4ecfe4c4
\ No newline at end of file
diff --git a/lib/javax-inject-src.jar b/lib/javax-inject-src.jar
new file mode 100644
index 0000000..a8a5aa7
--- /dev/null
+++ b/lib/javax-inject-src.jar
Binary files differ
diff --git a/lib/javax-inject.jar b/lib/javax-inject.jar
new file mode 100644
index 0000000..4c86c52
--- /dev/null
+++ b/lib/javax-inject.jar
Binary files differ
diff --git a/lib/NOTICE b/lib/javax-inject.jar.txt
similarity index 100%
copy from lib/NOTICE
copy to lib/javax-inject.jar.txt
diff --git a/lib/javax.inject-1-sources.jar b/lib/javax.inject-1-sources.jar
deleted file mode 100644
index 0c98053..0000000
--- a/lib/javax.inject-1-sources.jar
+++ /dev/null
Binary files differ
diff --git a/lib/javax.inject-1-sources.jar.sha1 b/lib/javax.inject-1-sources.jar.sha1
deleted file mode 100644
index b69cdf0..0000000
--- a/lib/javax.inject-1-sources.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-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
deleted file mode 100644
index b2a9d0b..0000000
--- a/lib/javax.inject-1.jar
+++ /dev/null
Binary files differ
diff --git a/lib/javax.inject-1.jar.sha1 b/lib/javax.inject-1.jar.sha1
deleted file mode 100644
index 41e75ef..0000000
--- a/lib/javax.inject-1.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6975da39a7040257bd51d21a231b76c915872d38 /home/maven/repository-staging/to-ibiblio/maven2/javax/inject/javax.inject/1/javax.inject-1.jar
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..fcdfe0c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 Square, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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>7</version>
+ </parent>
+
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <packaging>pom</packaging>
+ <version>2.1-SNAPSHOT</version>
+ <name>Dagger (Parent)</name>
+ <description>A fast dependency injector for Android and Java.</description>
+ <url>https://github.com/square/dagger</url>
+
+ <modules>
+ <module>compiler</module>
+ <module>core</module>
+ <!-- examples are handled in a default profile (see below) -->
+ <module>producers</module>
+ </modules>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+ <!-- Compilation -->
+ <java.version>1.7</java.version>
+ <javax.inject.version>1</javax.inject.version>
+ <javax.annotation.version>2.0.1</javax.annotation.version>
+ <javawriter.version>2.5.0</javawriter.version>
+ <auto.common.version>1.0-SNAPSHOT</auto.common.version>
+ <auto.factory.version>1.0-beta3</auto.factory.version>
+ <auto.service.version>1.0-rc2</auto.service.version>
+ <auto.value.version>1.0</auto.value.version>
+ <guava.version>18.0</guava.version>
+ <google.java.format.version>0.1-SNAPSHOT</google.java.format.version>
+
+ <!-- Test Dependencies -->
+ <compile-testing.version>1.0-SNAPSHOT</compile-testing.version>
+ <junit.version>4.11</junit.version>
+ <mockito.version>1.9.5</mockito.version>
+ <truth.version>0.26</truth.version>
+ </properties>
+
+ <scm>
+ <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>
+ </scm>
+
+ <issueManagement>
+ <system>GitHub Issues</system>
+ <url>http://github.com/google/dagger/issues</url>
+ </issueManagement>
+
+ <licenses>
+ <license>
+ <name>Apache 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+ <organization>
+ <name>Google, Inc.</name>
+ <url>http://www.google.com</url>
+ </organization>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>${javax.inject.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject-tck</artifactId>
+ <version>${javax.inject.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>${javax.annotation.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup</groupId>
+ <artifactId>javawriter</artifactId>
+ <version>${javawriter.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.googlejavaformat</groupId>
+ <artifactId>google-java-format</artifactId>
+ <version>${google.java.format.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto</groupId>
+ <artifactId>auto-common</artifactId>
+ <version>${auto.common.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.service</groupId>
+ <artifactId>auto-service</artifactId>
+ <version>${auto.service.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>${auto.value.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.testing.compile</groupId>
+ <artifactId>compile-testing</artifactId>
+ <version>${compile-testing.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>${mockito.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <version>${truth.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.7</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ <compilerArgument>-Xlint:all</compilerArgument>
+ <showWarnings>true</showWarnings>
+ <showDeprecation>true</showDeprecation>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.3.2</version><!--$NO-MVN-MAN-VER$-->
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <doctitle>Dagger Dependency Injection ${project.version} API</doctitle>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.10</version>
+ <configuration>
+ <failsOnError>false</failsOnError>
+ <consoleOutput>true</consoleOutput>
+ <configLocation>checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <!--
+ A profile which when switched off excludes example modules. By default the profile
+ is on and invokes examples. However, when processing javadocs, it is switched off
+ omitting the example code from the javadoc.
+ -->
+ <profiles>
+ <profile>
+ <id>examples</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <modules>
+ <module>core</module>
+ <module>compiler</module>
+ <module>examples</module>
+ <module>producers</module>
+ </modules>
+ </profile>
+ </profiles>
+</project>
diff --git a/producers/pom.xml b/producers/pom.xml
new file mode 100644
index 0000000..edaeca4
--- /dev/null
+++ b/producers/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2014 Google, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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</groupId>
+ <artifactId>dagger-parent</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>dagger-producers</artifactId>
+ <name>Dagger Production Graphs</name>
+ <description>
+ An asynchronous dependency injection system that extends JSR-330.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth</groupId>
+ <artifactId>truth</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/producers/src/main/java/dagger/producers/Produced.java b/producers/src/main/java/dagger/producers/Produced.java
new file mode 100644
index 0000000..db5c133
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Produced.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import com.google.common.base.Objects;
+import dagger.internal.Beta;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * An interface that represents the result of a {@linkplain Producer production} of type {@code T},
+ * or an exception that was thrown during that production. For any type {@code T} that can be
+ * injected, you can also inject {@code Produced<T>}, which enables handling of any exceptions that
+ * were thrown during the production of {@code T}.
+ *
+ * <p>For example: <pre><code>
+ * {@literal @}Produces Html getResponse(
+ * UserInfo criticalInfo, {@literal Produced<ExtraInfo>} noncriticalInfo) {
+ * try {
+ * return new Html(criticalInfo, noncriticalInfo.get());
+ * } catch (ExecutionException e) {
+ * logger.warning(e, "Noncritical info");
+ * return new Html(criticalInfo);
+ * }
+ * }
+ * </code></pre>
+ *
+ * @author Jesse Beder
+ */
+@Beta
+public abstract class Produced<T> {
+ /**
+ * Returns the result of a production.
+ *
+ * @throws ExecutionException if the production threw an exception
+ */
+ public abstract T get() throws ExecutionException;
+
+ /**
+ * Two {@code Produced} objects compare equal if both are successful with equal values, or both
+ * are failed with equal exceptions.
+ */
+ @Override
+ public abstract boolean equals(Object o);
+
+ /** Returns an appropriate hash code to match {@link #equals). */
+ @Override
+ public abstract int hashCode();
+
+ /** Returns a successful {@code Produced}, whose {@link #get} will return the given value. */
+ public static <T> Produced<T> successful(@Nullable T value) {
+ return new Successful<T>(value);
+ }
+
+ /**
+ * Returns a failed {@code Produced}, whose {@link #get} will throw an
+ * {@code ExecutionException} with the given cause.
+ */
+ public static <T> Produced<T> failed(Throwable throwable) {
+ return new Failed<T>(checkNotNull(throwable));
+ }
+
+ private static final class Successful<T> extends Produced<T> {
+ @Nullable private final T value;
+
+ private Successful(@Nullable T value) {
+ this.value = value;
+ }
+
+ @Override public T get() {
+ return value;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof Successful) {
+ Successful<?> that = (Successful<?>) o;
+ return Objects.equal(this.value, that.value);
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return value == null ? 0 : value.hashCode();
+ }
+ }
+
+ private static final class Failed<T> extends Produced<T> {
+ private final Throwable throwable;
+
+ private Failed(Throwable throwable) {
+ this.throwable = checkNotNull(throwable);
+ }
+
+ @Override public T get() throws ExecutionException {
+ throw new ExecutionException(throwable);
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof Failed) {
+ Failed<?> that = (Failed<?>) o;
+ return this.throwable.equals(that.throwable);
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return throwable.hashCode();
+ }
+ }
+
+ private Produced() {}
+}
diff --git a/producers/src/main/java/dagger/producers/Producer.java b/producers/src/main/java/dagger/producers/Producer.java
new file mode 100644
index 0000000..eb159bb
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Producer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import dagger.internal.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * An interface that represents the production of a type {@code T}. You can also inject
+ * {@code Producer<T>} instead of {@code T}, which will delay the execution of any code that
+ * produces the {@code T} until {@link #get} is called.
+ *
+ * <p>For example, you might inject {@code Producer} to lazily choose between several different
+ * implementations of some type: <pre><code>
+ * {@literal @Produces ListenableFuture<Heater>} getHeater(
+ * HeaterFlag flag,
+ * {@literal @Electric Producer<Heater>} electricHeater,
+ * {@literal @Gas Producer<Heater>} gasHeater) {
+ * return flag.useElectricHeater() ? electricHeater.get() : gasHeater.get();
+ * }
+ * </code></pre>
+ *
+ * <p>Here is a complete example that demonstrates how calling {@code get()} will cause each
+ * method to be executed: <pre><code>
+ *
+ * {@literal @}ProducerModule
+ * final class MyModule {
+ * {@literal @Produces ListenableFuture<A>} a() {
+ * System.out.println("a");
+ * return Futures.immediateFuture(new A());
+ * }
+ *
+ * {@literal @Produces ListenableFuture<B>} b(A a) {
+ * System.out.println("b");
+ * return Futures.immediateFuture(new B(a));
+ * }
+ *
+ * {@literal @Produces ListenableFuture<C>} c(B b) {
+ * System.out.println("c");
+ * return Futures.immediateFuture(new C(b));
+ * }
+ *
+ * {@literal @Produces @Delayed ListenableFuture<C>} delayedC(A a, {@literal Producer<C>} c) {
+ * System.out.println("delayed c");
+ * return c.get();
+ * }
+ * }
+ *
+ * {@literal @}ProductionComponent(modules = MyModule.class)
+ * interface MyComponent {
+ * {@literal @Delayed ListenableFuture<C>} delayedC();
+ * }
+ * </code></pre>
+ * Suppose we instantiate the generated implementation of this component and call
+ * {@code delayedC()}: <pre><code>
+ * MyComponent component = DaggerMyComponent
+ * .builder()
+ * .executor(MoreExecutors.directExecutor())
+ * .build();
+ * System.out.println("Constructed component");
+ * {@literal ListenableFuture<C>} cFuture = component.delayedC();
+ * System.out.println("Retrieved future");
+ * C c = cFuture.get();
+ * System.out.println("Retrieved c");
+ * </code></pre>
+ * Here, we're using {@code MoreExecutors.directExecutor} in order to illustrate how each call
+ * directly causes code to execute. The above code will print: <pre><code>
+ * Constructed component
+ * a
+ * delayed c
+ * b
+ * c
+ * Retrieved future
+ * Retrieved c
+ * </code></pre>
+ *
+ * @author Jesse Beder
+ */
+@Beta
+public interface Producer<T> {
+ /**
+ * Returns a future representing a running task that produces a value. Calling this method will
+ * trigger the submission of this task to the executor, if it has not already been triggered. In
+ * order to trigger this task's submission, the transitive dependencies required to produce the
+ * {@code T} will be submitted to the executor, as their dependencies become available.
+ *
+ * <p>If the key is bound to a {@link Produces} method, then calling this method multiple times
+ * will return the same future.
+ */
+ ListenableFuture<T> get();
+}
diff --git a/producers/src/main/java/dagger/producers/ProducerModule.java b/producers/src/main/java/dagger/producers/ProducerModule.java
new file mode 100644
index 0000000..714e3fa
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/ProducerModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import dagger.Module;
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Annotates a class that contributes {@link Produces} bindings to the production component.
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(TYPE)
+@Beta
+public @interface ProducerModule {
+ /**
+ * Additional {@code @ProducerModule}- or {@link Module}-annotated classes from which this module
+ * is composed. The de-duplicated contributions of the modules in {@code includes}, and of their
+ * inclusions recursively, are all contributed to the object graph.
+ */
+ Class<?>[] includes() default {};
+}
diff --git a/producers/src/main/java/dagger/producers/Produces.java b/producers/src/main/java/dagger/producers/Produces.java
new file mode 100644
index 0000000..1b57bc3
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/Produces.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import dagger.internal.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * Annotates methods of a producer module to create a production binding. If the method returns
+ * a {@link ListenableFuture}, then the parameter type of the future is bound to the value that the
+ * future provides; otherwise, the return type is bound to the returned value. The production
+ * component will pass dependencies to the method as parameters.
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(METHOD)
+@Beta
+public @interface Produces {
+ /** The type of binding into which the return type of the annotated method contributes. */
+ enum Type {
+ /**
+ * The method is the only one which can produce the value for the specified type. This is the
+ * default behavior.
+ */
+ UNIQUE,
+
+ /**
+ * The method's resulting type forms the generic type argument of a {@code Set<T>}, and the
+ * returned value or future is contributed to the set. The {@code Set<T>} produced from the
+ * accumulation of values will be immutable.
+ */
+ SET,
+
+ /**
+ * Like {@link #SET}, except the method's return type is either {@code Set<T>} or
+ * {@code Set<ListenableFuture<T>>}, where any values are contributed to the set. An example use
+ * is to provide a default empty set binding, which is otherwise not possible using
+ * {@link #SET}.
+ */
+ SET_VALUES,
+
+ /**
+ * The method's return type forms the type argument for the value of a
+ * {@code Map<K, Producer<V>>}, and the combination of the annotated key and the returned value
+ * is contributed to the map as a key/value pair. The {@code Map<K, Producer<V>>} produced from
+ * the accumulation of values will be immutable.
+ */
+ MAP;
+ }
+
+ Type type() default Type.UNIQUE;
+}
diff --git a/producers/src/main/java/dagger/producers/ProductionComponent.java b/producers/src/main/java/dagger/producers/ProductionComponent.java
new file mode 100644
index 0000000..8ccdb44
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/ProductionComponent.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.Beta;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import javax.inject.Inject;
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * Annotates an interface or abstract class for which a fully-formed, dependency-injected
+ * implementation is to be generated from a set of {@linkplain #modules}. The generated class will
+ * have the name of the type annotated with {@code @ProductionComponent} prepended with
+ * {@code Dagger}. For example, {@code @ProductionComponent interface MyComponent {...}} will
+ * produce an implementation named {@code DaggerMyComponent}.
+ *
+ * <p>Each {@link Produces} method that contributes to the component will be called at most once per
+ * component instance, no matter how many times that binding is used as a dependency.
+ * TODO(user): Decide on how scope works for producers.
+ *
+ * <h2>Component methods</h2>
+ *
+ * <p>Every type annotated with {@code @ProductionComponent} must contain at least one abstract
+ * component method. Component methods must represent {@linkplain Producer production}.
+ *
+ * Production methods have no arguments and return either a {@link ListenableFuture} or
+ * {@link Producer} of a type that is {@link Inject injected}, {@link Provides provided}, or
+ * {@link Produces produced}. Each may have a {@link Qualifier} annotation as well. The following
+ * are all valid production method declarations: <pre><code>
+ * ListenableFuture<SomeType> getSomeType();
+ * {@literal Producer<Set<SomeType>>} getSomeTypes();
+ * {@literal @Response ListenableFuture<Html>} getResponse();
+ * </code></pre>
+ *
+ * <h2>Exceptions</h2>
+ *
+ * <p>When a producer throws an exception, the exception will be propagated to its downstream
+ * producers in the following way: if the downstream producer injects a type {@code T}, then that
+ * downstream producer will be skipped, and the exception propagated to its downstream producers;
+ * and if the downstream producer injects a {@code Produced<T>}, then the downstream producer will
+ * be run with the exception stored in the {@code Produced<T>}.
+ *
+ * <p>If a non-execution exception is thrown (e.g., an {@code InterruptedException} or
+ * {@code CancellationException}), then exception is handled as in
+ * {@link com.google.common.util.concurrent.Futures#transform}.
+ * <!-- TODO(beder): Explain this more thoroughly, and update the javadocs of those utilities. -->
+ *
+ * @author Jesse Beder
+ */
+@Documented
+@Target(TYPE)
+@Beta
+public @interface ProductionComponent {
+ /**
+ * A list of classes annotated with {@link Module} or {@link ProducerModule} whose bindings are
+ * used to generate the component implementation.
+ */
+ Class<?>[] modules() default {};
+
+ /**
+ * A list of types that are to be used as component dependencies.
+ */
+ Class<?>[] dependencies() default {};
+
+ /**
+ * A builder for a component. Components may have a single nested static abstract class or
+ * interface annotated with {@code @ProductionComponent.Builder}. If they do, then the component's
+ * generated builder will match the API in the type. Builders must follow some rules:
+ * <ul>
+ * <li> A single abstract method with no arguments must exist, and must return the component.
+ * (This is typically the {@code build()} method.)
+ * <li> All other abstract methods must take a single argument and must return void,
+ * the builder type, or a supertype of the builder.
+ * <li> There <b>must</b> be an abstract method whose parameter is
+ * {@link java.util.concurrent.Executor}.
+ * <li> Each component dependency <b>must</b> have an abstract setter method.
+ * <li> Each module dependency that Dagger can't instantiate itself (i.e., the module
+ * doesn't have a visible no-args constructor) <b>must</b> have an abstract setter method.
+ * Other module dependencies (ones that Dagger can instantiate) are allowed, but not
+ * required.
+ * <li> Non-abstract methods are allowed, but ignored as far as validation and builder generation
+ * are concerned.
+ * </ul>
+ *
+ * For example, this could be a valid {@code ProductionComponent} with a builder: <pre><code>
+ * {@literal @}ProductionComponent(modules = {BackendModule.class, FrontendModule.class})
+ * interface MyComponent {
+ * {@literal ListenableFuture<MyWidget>} myWidget();
+ *
+ * {@literal @}ProductionComponent.Builder
+ * interface Builder {
+ * MyComponent build();
+ * Builder executor(Executor executor);
+ * Builder backendModule(BackendModule bm);
+ * Builder frontendModule(FrontendModule fm);
+ * }
+ * }</code></pre>
+ */
+ @Target(TYPE)
+ @Documented
+ @interface Builder {}
+}
diff --git a/producers/src/main/java/dagger/producers/internal/AbstractProducer.java b/producers/src/main/java/dagger/producers/internal/AbstractProducer.java
new file mode 100644
index 0000000..f7e8ec0
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/AbstractProducer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import dagger.producers.monitoring.internal.Monitors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nullable;
+import javax.inject.Provider;
+
+/**
+ * An abstract {@link Producer} implementation that memoizes the result of its compute method.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public abstract class AbstractProducer<T> implements Producer<T> {
+ private final Provider<ProductionComponentMonitor> monitorProvider;
+ @Nullable private final ProducerToken token;
+ private volatile ListenableFuture<T> instance = null;
+
+ protected AbstractProducer() {
+ this(Monitors.noOpProductionComponentMonitorProvider(), null);
+ }
+
+ protected AbstractProducer(
+ Provider<ProductionComponentMonitor> monitorProvider, @Nullable ProducerToken token) {
+ this.monitorProvider = checkNotNull(monitorProvider);
+ this.token = token;
+ }
+
+ /** Computes this producer's future, which is then cached in {@link #get}. */
+ protected abstract ListenableFuture<T> compute(ProducerMonitor monitor);
+
+ @Override
+ public final ListenableFuture<T> get() {
+ // double-check idiom from EJ2: Item 71
+ ListenableFuture<T> result = instance;
+ if (result == null) {
+ synchronized (this) {
+ result = instance;
+ if (result == null) {
+ ProducerMonitor monitor = monitorProvider.get().producerMonitorFor(token);
+ instance = result = compute(monitor);
+ if (result == null) {
+ throw new NullPointerException("compute returned null");
+ }
+ monitor.addCallbackTo(result);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/internal/Producers.java b/producers/src/main/java/dagger/producers/internal/Producers.java
new file mode 100644
index 0000000..7052c35
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/Producers.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.FutureFallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import java.util.Set;
+import javax.inject.Provider;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility methods for use in generated producer code.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public final class Producers {
+ /**
+ * Returns a future of {@link Produced} that represents the completion (either success or failure)
+ * of the given future. If the input future succeeds, then the resulting future also succeeds with
+ * a successful {@code Produced}; if the input future fails, then the resulting future succeeds
+ * with a failing {@code Produced}.
+ *
+ * <p>Cancelling the resulting future will propagate the cancellation to the input future; but
+ * cancelling the input future will trigger the resulting future to succeed with a failing
+ * {@code Produced}.
+ */
+ // TODO(user): Document what happens with an InterruptedException after you figure out how to
+ // trigger one in a test.
+ public static <T> ListenableFuture<Produced<T>> createFutureProduced(ListenableFuture<T> future) {
+ // TODO(dpb): Switch to Futures.catchAsync once guava_jdk5 gets to v19.
+ return Futures.withFallback(
+ Futures.transform(
+ future,
+ new Function<T, Produced<T>>() {
+ @Override
+ public Produced<T> apply(final T value) {
+ return Produced.successful(value);
+ }
+ }),
+ Producers.<T>futureFallbackForProduced());
+
+ }
+
+ private static final FutureFallback<Produced<Object>> FUTURE_FALLBACK_FOR_PRODUCED =
+ new FutureFallback<Produced<Object>>() {
+ @Override public ListenableFuture<Produced<Object>> create(final Throwable t) {
+ Produced<Object> produced = Produced.failed(t);
+ return Futures.immediateFuture(produced);
+ }
+ };
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
+ private static <T> FutureFallback<Produced<T>> futureFallbackForProduced() {
+ return (FutureFallback) FUTURE_FALLBACK_FOR_PRODUCED;
+ }
+
+ /**
+ * Returns a future of a {@code Set} that contains a single element: the result of the input
+ * future.
+ */
+ public static <T> ListenableFuture<Set<T>> createFutureSingletonSet(ListenableFuture<T> future) {
+ return Futures.transform(future, new Function<T, Set<T>>() {
+ @Override public Set<T> apply(T value) {
+ return ImmutableSet.of(value);
+ }
+ });
+ }
+
+ /**
+ * Returns a producer that immediately executes the binding logic for the given provider every
+ * time it is called.
+ */
+ public static <T> Producer<T> producerFromProvider(final Provider<T> provider) {
+ checkNotNull(provider);
+ return new AbstractProducer<T>() {
+ @Override
+ protected ListenableFuture<T> compute(ProducerMonitor unusedMonitor) {
+ return Futures.immediateFuture(provider.get());
+ }
+ };
+ }
+
+ /** Returns a producer that succeeds with the given value. */
+ public static <T> Producer<T> immediateProducer(final T value) {
+ return new Producer<T>() {
+ @Override
+ public ListenableFuture<T> get() {
+ return Futures.immediateFuture(value);
+ }
+ };
+ }
+
+ /** Returns a producer that fails with the given exception. */
+ public static <T> Producer<T> immediateFailedProducer(final Throwable throwable) {
+ return new Producer<T>() {
+ @Override
+ public ListenableFuture<T> get() {
+ return Futures.immediateFailedFuture(throwable);
+ }
+ };
+ }
+
+ private Producers() {}
+}
diff --git a/producers/src/main/java/dagger/producers/internal/SetOfProducedProducer.java b/producers/src/main/java/dagger/producers/internal/SetOfProducedProducer.java
new file mode 100644
index 0000000..e51bcad
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/SetOfProducedProducer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns a
+ * future {@code Set<Produced<T>>} whose elements are populated by subsequent calls to the delegate
+ * {@link Producer#get} methods.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public final class SetOfProducedProducer<T> extends AbstractProducer<Set<Produced<T>>> {
+ /**
+ * Returns a new producer that creates {@link Set} futures from the union of the given
+ * {@link Producer} instances.
+ */
+ @SafeVarargs
+ public static <T> Producer<Set<Produced<T>>> create(Producer<Set<T>>... producers) {
+ return new SetOfProducedProducer<T>(ImmutableSet.copyOf(producers));
+ }
+
+ private final ImmutableSet<Producer<Set<T>>> contributingProducers;
+
+ private SetOfProducedProducer(ImmutableSet<Producer<Set<T>>> contributingProducers) {
+ this.contributingProducers = contributingProducers;
+ }
+
+ /**
+ * Returns a future {@link Set} of {@link Produced} values whose iteration order is that of the
+ * elements given by each of the producers, which are invoked in the order given at creation.
+ *
+ * <p>If any of the delegate sets, or any elements therein, are null, then that corresponding
+ * {@code Produced} element will fail with a NullPointerException.
+ *
+ * <p>Canceling this future will attempt to cancel all of the component futures; but if any of the
+ * delegate futures fail or are canceled, this future succeeds, with the appropriate failed
+ * {@link Produced}.
+ *
+ * @throws NullPointerException if any of the delegate producers return null
+ */
+ @Override
+ public ListenableFuture<Set<Produced<T>>> compute(ProducerMonitor unusedMonitor) {
+ List<ListenableFuture<Produced<Set<T>>>> futureProducedSets =
+ new ArrayList<ListenableFuture<Produced<Set<T>>>>(contributingProducers.size());
+ for (Producer<Set<T>> producer : contributingProducers) {
+ ListenableFuture<Set<T>> futureSet = producer.get();
+ if (futureSet == null) {
+ throw new NullPointerException(producer + " returned null");
+ }
+ futureProducedSets.add(Producers.createFutureProduced(futureSet));
+ }
+ return Futures.transform(
+ Futures.allAsList(futureProducedSets),
+ new Function<List<Produced<Set<T>>>, Set<Produced<T>>>() {
+ @Override
+ public Set<Produced<T>> apply(List<Produced<Set<T>>> producedSets) {
+ ImmutableSet.Builder<Produced<T>> builder = ImmutableSet.builder();
+ for (Produced<Set<T>> producedSet : producedSets) {
+ try {
+ Set<T> set = producedSet.get();
+ if (set == null) {
+ // TODO(beder): This is a vague exception. Can we somehow point to the failing
+ // producer? See the similar comment in the component writer about null
+ // provisions.
+ builder.add(
+ Produced.<T>failed(
+ new NullPointerException(
+ "Cannot contribute a null set into a producer set binding when it's"
+ + " injected as Set<Produced<T>>.")));
+ } else {
+ for (T value : set) {
+ if (value == null) {
+ builder.add(
+ Produced.<T>failed(
+ new NullPointerException(
+ "Cannot contribute a null element into a producer set binding"
+ + " when it's injected as Set<Produced<T>>.")));
+ } else {
+ builder.add(Produced.successful(value));
+ }
+ }
+ }
+ } catch (ExecutionException e) {
+ builder.add(Produced.<T>failed(e.getCause()));
+ }
+ }
+ return builder.build();
+ }
+ });
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/internal/SetProducer.java b/producers/src/main/java/dagger/producers/internal/SetProducer.java
new file mode 100644
index 0000000..5b3c090
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/internal/SetProducer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A {@link Producer} implementation used to implement {@link Set} bindings. This producer returns
+ * a future {@link Set} whose elements are populated by subsequent calls to the delegate
+ * {@link Producer#get} methods.
+ *
+ * @author Jesse Beder
+ * @since 2.0
+ */
+public final class SetProducer<T> extends AbstractProducer<Set<T>> {
+ /**
+ * Returns a new producer that creates {@link Set} futures from the union of the given
+ * {@link Producer} instances.
+ */
+ @SafeVarargs
+ public static <T> Producer<Set<T>> create(Producer<Set<T>>... producers) {
+ return new SetProducer<T>(ImmutableSet.copyOf(producers));
+ }
+
+ private final Set<Producer<Set<T>>> contributingProducers;
+
+ private SetProducer(Set<Producer<Set<T>>> contributingProducers) {
+ super();
+ this.contributingProducers = contributingProducers;
+ }
+
+ /**
+ * Returns a future {@link Set} whose iteration order is that of the elements given by each of the
+ * producers, which are invoked in the order given at creation.
+ *
+ * <p>If any of the delegate sets, or any elements therein, are null, then this future will fail
+ * with a NullPointerException.
+ *
+ * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the
+ * delegate futures fails or is canceled, this one is, too.
+ *
+ * @throws NullPointerException if any of the delegate producers return null
+ */
+ @Override
+ public ListenableFuture<Set<T>> compute(ProducerMonitor unusedMonitor) {
+ List<ListenableFuture<Set<T>>> futureSets =
+ new ArrayList<ListenableFuture<Set<T>>>(contributingProducers.size());
+ for (Producer<Set<T>> producer : contributingProducers) {
+ ListenableFuture<Set<T>> futureSet = producer.get();
+ if (futureSet == null) {
+ throw new NullPointerException(producer + " returned null");
+ }
+ futureSets.add(futureSet);
+ }
+ return Futures.transform(Futures.allAsList(futureSets), new Function<List<Set<T>>, Set<T>>() {
+ @Override public Set<T> apply(List<Set<T>> sets) {
+ ImmutableSet.Builder<T> builder = ImmutableSet.builder();
+ for (Set<T> set : sets) {
+ builder.addAll(set);
+ }
+ return builder.build();
+ }
+ });
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java b/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java
new file mode 100644
index 0000000..20551c3
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProducerMonitor.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Produces;
+
+/**
+ * A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
+ * {@link ProductionComponentMonitor} for how to install these monitors.
+ *
+ * <p>The lifecycle of the monitor, under normal conditions, is:
+ * <ul>
+ * <li>{@link #methodStarting()}
+ * <li>The method is called
+ * <li>{@link #methodFinished()}
+ * <li>If the method returns a value, then:
+ * <ul>
+ * <li>{@link #succeeded(Object)} if the method returned normally; or
+ * <li>{@link #failed(Throwable)} if the method threw an exception.
+ * </ul>
+ * <li>If the method returns a future, then:
+ * <ul>
+ * <li>{@link #succeeded(Object)} if the method returned normally, and the future succeeded; or
+ * <li>{@link #failed(Throwable)} if the method threw an exception, or returned normally and the
+ * future failed.
+ * </ul>
+ * </ul>
+ *
+ * <p>If any input to the monitored producer fails, {@link #failed(Throwable)} will be called
+ * immediately with the failed input's exception. If more than one input fails, an arbitrary failed
+ * input's exception is used.
+ *
+ * <p>If any of the monitor's methods throw, then the exception will be logged and processing will
+ * continue unaffected.
+ *
+ * @author Jesse Beder
+ */
+public abstract class ProducerMonitor {
+ /**
+ * Called when the producer method is about to start executing.
+ *
+ * <p>When multiple monitors are installed, the order that each monitor will call this method is
+ * unspecified, but will remain consistent throughout the course of the execution of a component.
+ */
+ public void methodStarting() {}
+
+ /**
+ * Called when the producer method has finished executing.
+ *
+ * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
+ * calls to {@link #methodStarting()}.
+ */
+ public void methodFinished() {}
+
+ /**
+ * Called when the producer’s future has completed successfully with a value.
+ *
+ * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
+ * calls to {@link #methodStarting()}.
+ */
+ public void succeeded(Object o) {}
+
+ /**
+ * Called when the producer's future has failed with an exception.
+ *
+ * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
+ * calls to {@link #methodStarting()}.
+ */
+ public void failed(Throwable t) {}
+
+ /**
+ * Adds this monitor's completion methods as a callback to the future. This is only intended to be
+ * overridden in the framework!
+ */
+ public <T> void addCallbackTo(ListenableFuture<T> future) {
+ Futures.addCallback(
+ future,
+ new FutureCallback<T>() {
+ @Override
+ public void onSuccess(T value) {
+ succeeded(value);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ failed(t);
+ }
+ });
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java b/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java
new file mode 100644
index 0000000..5834206
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProducerToken.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring;
+
+import dagger.producers.Produces;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/** A token that represents an individual {@linkplain Produces producer method}. */
+public final class ProducerToken {
+ private final Class<?> classToken;
+
+ private ProducerToken(Class<?> classToken) {
+ this.classToken = classToken;
+ }
+
+ /**
+ * Creates a token for a class token that represents the generated factory for a producer method.
+ *
+ * <p><b>Do not use this!</b> This is intended to be called by generated code only, and its
+ * signature may change at any time.
+ */
+ public static ProducerToken create(Class<?> classToken) {
+ return new ProducerToken(checkNotNull(classToken));
+ }
+
+ /** Two tokens are equal if they represent the same method. */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof ProducerToken) {
+ ProducerToken that = (ProducerToken) o;
+ return this.classToken.equals(that.classToken);
+ } else {
+ return false;
+ }
+ }
+
+ /** Returns an appropriate hash code to match {@link #equals). */
+ @Override
+ public int hashCode() {
+ return classToken.hashCode();
+ }
+
+ /** Returns a representation of the method. */
+ @Override
+ public String toString() {
+ return classToken.toString();
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java b/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java
new file mode 100644
index 0000000..4dc2903
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/ProductionComponentMonitor.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring;
+
+import dagger.producers.Produces;
+import dagger.producers.ProductionComponent;
+
+/**
+ * A hook for monitoring execution of {@linkplain ProductionComponent production components}. To
+ * install a {@code ProductionComponentMonitor}, contribute to a set binding of
+ * {@code ProductionComponentMonitor.Factory}. The factory will be asked to create one monitor for
+ * the component, and the resulting single instance will be used to create individual monitors for
+ * producers.
+ *
+ * <p>For example: <pre><code>
+ * {@literal @Module}
+ * final class MyMonitorModule {
+ * {@literal @Provides(type = SET)} ProductionComponentMonitor.Factory provideMonitorFactory(
+ * MyProductionComponentMonitor.Factory monitorFactory) {
+ * return monitorFactory;
+ * }
+ * }
+ *
+ * {@literal @ProductionComponent(modules = {MyMonitorModule.class, MyProducerModule.class})}
+ * interface MyComponent {
+ * {@literal ListenableFuture<SomeType>} someType();
+ * }
+ * </code></pre>
+ *
+ * <p>If any of these methods throw, then the exception will be logged, and the framework will act
+ * as though a no-op monitor was returned.
+ *
+ * @author Jesse Beder
+ */
+public interface ProductionComponentMonitor {
+ /** Returns a monitor for an individual {@linkplain Produces producer method}. */
+ ProducerMonitor producerMonitorFor(ProducerToken token);
+
+ public interface Factory {
+ /** Creates a component-specific monitor when the component is created. */
+ ProductionComponentMonitor create(Object component);
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/internal/MonitorCache.java b/producers/src/main/java/dagger/producers/monitoring/internal/MonitorCache.java
new file mode 100644
index 0000000..2a76c5f
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/internal/MonitorCache.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring.internal;
+
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Provider;
+
+/**
+ * A class that provides a {@link ProductionComponentMonitor} for use in production components.
+ *
+ * <p>This caches the underlying the monitor, since we want a single instance for each component.
+ */
+public final class MonitorCache {
+ private static final Logger logger = Logger.getLogger(MonitorCache.class.getName());
+
+ private volatile ProductionComponentMonitor monitor;
+
+ /**
+ * Returns the underlying monitor. This will only actually compute the monitor the first time it
+ * is called; subsequent calls will simply return the cached value, so the arguments to this
+ * method are ignored. It is expected (though not checked) that this method is called with
+ * equivalent arguments each time (like a {@link dagger.Provides @Provides} method would).
+ */
+ public ProductionComponentMonitor monitor(
+ Provider<?> componentProvider,
+ Provider<Set<ProductionComponentMonitor.Factory>> monitorFactorySetProvider) {
+ ProductionComponentMonitor result = monitor;
+ if (result == null) {
+ synchronized (this) {
+ result = monitor;
+ if (result == null) {
+ try {
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ monitorFactorySetProvider.get());
+ result = monitor = factory.create(componentProvider.get());
+ } catch (RuntimeException e) {
+ logger.log(Level.SEVERE, "RuntimeException while constructing monitor factories.", e);
+ result = monitor = Monitors.noOpProductionComponentMonitor();
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/internal/Monitors.java b/producers/src/main/java/dagger/producers/monitoring/internal/Monitors.java
new file mode 100644
index 0000000..f27ce37
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/internal/Monitors.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring.internal;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.inject.Provider;
+
+/**
+ * Utility methods relating to monitoring, for use in generated producers code.
+ *
+ * @author Jesse Beder
+ */
+public final class Monitors {
+ private static final Logger logger = Logger.getLogger(Monitors.class.getName());
+
+ /**
+ * Returns a monitor factory that delegates to the given factories, and ensures that any method
+ * called on this object, even transitively, does not throw a {@link RuntimeException} or return
+ * null.
+ *
+ * <p>If the delegate monitors throw an {@link Error}, then that will escape this monitor
+ * implementation. Errors are treated as unrecoverable conditions, and may cause the entire
+ * component's execution to fail.
+ */
+ public static ProductionComponentMonitor.Factory delegatingProductionComponentMonitorFactory(
+ Collection<? extends ProductionComponentMonitor.Factory> factories) {
+ if (factories.isEmpty()) {
+ return noOpProductionComponentMonitorFactory();
+ } else if (factories.size() == 1) {
+ return new NonThrowingProductionComponentMonitor.Factory(Iterables.getOnlyElement(factories));
+ } else {
+ return new DelegatingProductionComponentMonitor.Factory(factories);
+ }
+ }
+
+ /**
+ * A component monitor that delegates to a single monitor, and catches and logs all exceptions
+ * that the delegate throws.
+ */
+ private static final class NonThrowingProductionComponentMonitor
+ implements ProductionComponentMonitor {
+ private final ProductionComponentMonitor delegate;
+
+ NonThrowingProductionComponentMonitor(ProductionComponentMonitor delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ProducerMonitor producerMonitorFor(ProducerToken token) {
+ try {
+ ProducerMonitor monitor = delegate.producerMonitorFor(token);
+ return monitor == null ? noOpProducerMonitor() : new NonThrowingProducerMonitor(monitor);
+ } catch (RuntimeException e) {
+ logProducerMonitorForException(e, delegate, token);
+ return noOpProducerMonitor();
+ }
+ }
+
+ static final class Factory implements ProductionComponentMonitor.Factory {
+ private final ProductionComponentMonitor.Factory delegate;
+
+ Factory(ProductionComponentMonitor.Factory delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ProductionComponentMonitor create(Object component) {
+ try {
+ ProductionComponentMonitor monitor = delegate.create(component);
+ return monitor == null
+ ? noOpProductionComponentMonitor()
+ : new NonThrowingProductionComponentMonitor(monitor);
+ } catch (RuntimeException e) {
+ logCreateException(e, delegate, component);
+ return noOpProductionComponentMonitor();
+ }
+ }
+ }
+ }
+
+ /**
+ * A producer monitor that delegates to a single monitor, and catches and logs all exceptions
+ * that the delegate throws.
+ */
+ private static final class NonThrowingProducerMonitor extends ProducerMonitor {
+ private final ProducerMonitor delegate;
+
+ NonThrowingProducerMonitor(ProducerMonitor delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void methodStarting() {
+ try {
+ delegate.methodStarting();
+ } catch (RuntimeException e) {
+ logProducerMonitorMethodException(e, delegate, "methodStarting");
+ }
+ }
+
+ @Override
+ public void methodFinished() {
+ try {
+ delegate.methodFinished();
+ } catch (RuntimeException e) {
+ logProducerMonitorMethodException(e, delegate, "methodFinished");
+ }
+ }
+
+ @Override
+ public void succeeded(Object o) {
+ try {
+ delegate.succeeded(o);
+ } catch (RuntimeException e) {
+ logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
+ }
+ }
+
+ @Override
+ public void failed(Throwable t) {
+ try {
+ delegate.failed(t);
+ } catch (RuntimeException e) {
+ logProducerMonitorArgMethodException(e, delegate, "failed", t);
+ }
+ }
+ }
+
+ /**
+ * A component monitor that delegates to several monitors, and catches and logs all exceptions
+ * that the delegates throw.
+ */
+ private static final class DelegatingProductionComponentMonitor
+ implements ProductionComponentMonitor {
+ private final ImmutableList<ProductionComponentMonitor> delegates;
+
+ DelegatingProductionComponentMonitor(ImmutableList<ProductionComponentMonitor> delegates) {
+ this.delegates = delegates;
+ }
+
+ @Override
+ public ProducerMonitor producerMonitorFor(ProducerToken token) {
+ ImmutableList.Builder<ProducerMonitor> monitorsBuilder = ImmutableList.builder();
+ for (ProductionComponentMonitor delegate : delegates) {
+ try {
+ ProducerMonitor monitor = delegate.producerMonitorFor(token);
+ if (monitor != null) {
+ monitorsBuilder.add(monitor);
+ }
+ } catch (RuntimeException e) {
+ logProducerMonitorForException(e, delegate, token);
+ }
+ }
+ ImmutableList<ProducerMonitor> monitors = monitorsBuilder.build();
+ if (monitors.isEmpty()) {
+ return noOpProducerMonitor();
+ } else if (monitors.size() == 1) {
+ return new NonThrowingProducerMonitor(Iterables.getOnlyElement(monitors));
+ } else {
+ return new DelegatingProducerMonitor(monitors);
+ }
+ }
+
+ static final class Factory implements ProductionComponentMonitor.Factory {
+ private final ImmutableList<? extends ProductionComponentMonitor.Factory> delegates;
+
+ Factory(Iterable<? extends ProductionComponentMonitor.Factory> delegates) {
+ this.delegates = ImmutableList.copyOf(delegates);
+ }
+
+ @Override
+ public ProductionComponentMonitor create(Object component) {
+ ImmutableList.Builder<ProductionComponentMonitor> monitorsBuilder = ImmutableList.builder();
+ for (ProductionComponentMonitor.Factory delegate : delegates) {
+ try {
+ ProductionComponentMonitor monitor = delegate.create(component);
+ if (monitor != null) {
+ monitorsBuilder.add(monitor);
+ }
+ } catch (RuntimeException e) {
+ logCreateException(e, delegate, component);
+ }
+ }
+ ImmutableList<ProductionComponentMonitor> monitors = monitorsBuilder.build();
+ if (monitors.isEmpty()) {
+ return noOpProductionComponentMonitor();
+ } else if (monitors.size() == 1) {
+ return new NonThrowingProductionComponentMonitor(Iterables.getOnlyElement(monitors));
+ } else {
+ return new DelegatingProductionComponentMonitor(monitors);
+ }
+ }
+ }
+ }
+
+ /**
+ * A producer monitor that delegates to several monitors, and catches and logs all exceptions
+ * that the delegates throw.
+ */
+ private static final class DelegatingProducerMonitor extends ProducerMonitor {
+ private final ImmutableList<ProducerMonitor> delegates;
+
+ DelegatingProducerMonitor(ImmutableList<ProducerMonitor> delegates) {
+ this.delegates = delegates;
+ }
+
+ @Override
+ public void methodStarting() {
+ for (ProducerMonitor delegate : delegates) {
+ try {
+ delegate.methodStarting();
+ } catch (RuntimeException e) {
+ logProducerMonitorMethodException(e, delegate, "methodStarting");
+ }
+ }
+ }
+
+ @Override
+ public void methodFinished() {
+ for (ProducerMonitor delegate : delegates.reverse()) {
+ try {
+ delegate.methodFinished();
+ } catch (RuntimeException e) {
+ logProducerMonitorMethodException(e, delegate, "methodFinished");
+ }
+ }
+ }
+
+ @Override
+ public void succeeded(Object o) {
+ for (ProducerMonitor delegate : delegates.reverse()) {
+ try {
+ delegate.succeeded(o);
+ } catch (RuntimeException e) {
+ logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
+ }
+ }
+ }
+
+ @Override
+ public void failed(Throwable t) {
+ for (ProducerMonitor delegate : delegates.reverse()) {
+ try {
+ delegate.failed(t);
+ } catch (RuntimeException e) {
+ logProducerMonitorArgMethodException(e, delegate, "failed", t);
+ }
+ }
+ }
+ }
+
+ /** Returns a monitor factory that returns no-op component monitors. */
+ public static ProductionComponentMonitor.Factory noOpProductionComponentMonitorFactory() {
+ return NO_OP_PRODUCTION_COMPONENT_MONITOR_FACTORY;
+ }
+
+ /** Returns a component monitor that returns no-op producer monitors. */
+ public static ProductionComponentMonitor noOpProductionComponentMonitor() {
+ return NO_OP_PRODUCTION_COMPONENT_MONITOR;
+ }
+
+ /** Returns a producer monitor that does nothing. */
+ public static ProducerMonitor noOpProducerMonitor() {
+ return NO_OP_PRODUCER_MONITOR;
+ }
+
+ /** Returns a provider of a no-op component monitor. */
+ public static Provider<ProductionComponentMonitor> noOpProductionComponentMonitorProvider() {
+ return NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER;
+ }
+
+ private static final ProductionComponentMonitor.Factory
+ NO_OP_PRODUCTION_COMPONENT_MONITOR_FACTORY =
+ new ProductionComponentMonitor.Factory() {
+ @Override
+ public ProductionComponentMonitor create(Object component) {
+ return noOpProductionComponentMonitor();
+ }
+ };
+
+ private static final ProductionComponentMonitor NO_OP_PRODUCTION_COMPONENT_MONITOR =
+ new ProductionComponentMonitor() {
+ @Override
+ public ProducerMonitor producerMonitorFor(ProducerToken token) {
+ return noOpProducerMonitor();
+ }
+ };
+
+ private static final ProducerMonitor NO_OP_PRODUCER_MONITOR =
+ new ProducerMonitor() {
+ @Override
+ public <T> void addCallbackTo(ListenableFuture<T> future) {
+ // overridden to avoid adding a do-nothing callback
+ }
+ };
+
+ private static final Provider<ProductionComponentMonitor>
+ NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER =
+ new Provider() {
+ @Override
+ public ProductionComponentMonitor get() {
+ return noOpProductionComponentMonitor();
+ }
+ };
+
+ private static void logCreateException(
+ RuntimeException e, ProductionComponentMonitor.Factory factory, Object component) {
+ logger.log(
+ Level.SEVERE,
+ "RuntimeException while calling ProductionComponentMonitor.Factory.create on factory "
+ + factory
+ + " with component "
+ + component,
+ e);
+ }
+
+ private static void logProducerMonitorForException(
+ RuntimeException e, ProductionComponentMonitor monitor, ProducerToken token) {
+ logger.log(
+ Level.SEVERE,
+ "RuntimeException while calling ProductionComponentMonitor.producerMonitorFor on monitor "
+ + monitor
+ + " with token "
+ + token,
+ e);
+ }
+
+ private static void logProducerMonitorMethodException(
+ RuntimeException e, ProducerMonitor monitor, String method) {
+ logger.log(
+ Level.SEVERE,
+ "RuntimeException while calling ProducerMonitor." + method + " on monitor " + monitor,
+ e);
+ }
+
+ private static void logProducerMonitorArgMethodException(
+ RuntimeException e, ProducerMonitor monitor, String method, Object arg) {
+ logger.log(
+ Level.SEVERE,
+ "RuntimeException while calling ProducerMonitor."
+ + method
+ + " on monitor "
+ + monitor
+ + " with "
+ + arg,
+ e);
+ }
+
+ private Monitors() {}
+}
diff --git a/producers/src/main/java/dagger/producers/monitoring/package-info.java b/producers/src/main/java/dagger/producers/monitoring/package-info.java
new file mode 100644
index 0000000..d104087
--- /dev/null
+++ b/producers/src/main/java/dagger/producers/monitoring/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 provides hooks for monitoring producers.
+ *
+ * <p>The interfaces in this package are not stable. Do not use these interfaces unless you are
+ * prepared to be broken.
+ */
+package dagger.producers.monitoring;
diff --git a/producers/src/test/java/dagger/producers/ProducedTest.java b/producers/src/test/java/dagger/producers/ProducedTest.java
new file mode 100644
index 0000000..165e730
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/ProducedTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import com.google.common.testing.EqualsTester;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link Produced}.
+ */
+@RunWith(JUnit4.class)
+public class ProducedTest {
+ @Test public void successfulProduced() throws ExecutionException {
+ Object o = new Object();
+ assertThat(Produced.successful(5).get()).isEqualTo(5);
+ assertThat(Produced.successful("monkey").get()).isEqualTo("monkey");
+ assertThat(Produced.successful(o).get()).isSameAs(o);
+ }
+
+ @Test public void failedProduced() {
+ RuntimeException cause = new RuntimeException("monkey");
+ try {
+ Produced.failed(cause).get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(cause);
+ }
+ }
+
+ @Test public void producedEquivalence() {
+ RuntimeException e1 = new RuntimeException("monkey");
+ RuntimeException e2 = new CancellationException();
+ new EqualsTester()
+ .addEqualityGroup(Produced.successful(132435), Produced.successful(132435))
+ .addEqualityGroup(Produced.successful("hi"), Produced.successful("hi"))
+ .addEqualityGroup(Produced.failed(e1), Produced.failed(e1))
+ .addEqualityGroup(Produced.failed(e2), Produced.failed(e2))
+ .testEquals();
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java b/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java
new file mode 100644
index 0000000..923ea70
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/AbstractProducerTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Producer;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.concurrent.ExecutionException;
+import javax.inject.Provider;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests {@link AbstractProducer}.
+ */
+@RunWith(JUnit4.class)
+public class AbstractProducerTest {
+ @Mock private ProductionComponentMonitor componentMonitor;
+ private ProducerMonitor monitor;
+ private Provider<ProductionComponentMonitor> componentMonitorProvider;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
+ when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
+ componentMonitorProvider =
+ new Provider<ProductionComponentMonitor>() {
+ @Override
+ public ProductionComponentMonitor get() {
+ return componentMonitor;
+ }
+ };
+ }
+
+ @Test
+ public void get_nullPointerException() {
+ Producer<Object> producer = new DelegateProducer<>(componentMonitorProvider, null);
+ try {
+ producer.get();
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test public void get() throws Exception {
+ Producer<Integer> producer =
+ new AbstractProducer<Integer>(componentMonitorProvider, null) {
+ int i = 0;
+
+ @Override
+ public ListenableFuture<Integer> compute(ProducerMonitor unusedMonitor) {
+ return Futures.immediateFuture(i++);
+ }
+ };
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ }
+
+ @Test
+ public void monitor_success() throws Exception {
+ SettableFuture<Integer> delegateFuture = SettableFuture.create();
+ Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
+
+ ListenableFuture<Integer> future = producer.get();
+ assertThat(future.isDone()).isFalse();
+ verify(monitor).addCallbackTo(any(ListenableFuture.class));
+ delegateFuture.set(-42);
+ assertThat(future.get()).isEqualTo(-42);
+ verify(monitor).succeeded(-42);
+ verifyNoMoreInteractions(monitor);
+ }
+
+ @Test
+ public void monitor_failure() throws Exception {
+ SettableFuture<Integer> delegateFuture = SettableFuture.create();
+ Producer<Integer> producer = new DelegateProducer<>(componentMonitorProvider, delegateFuture);
+
+ ListenableFuture<Integer> future = producer.get();
+ assertThat(future.isDone()).isFalse();
+ verify(monitor).addCallbackTo(any(ListenableFuture.class));
+ Throwable t = new RuntimeException("monkey");
+ delegateFuture.setException(t);
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(t);
+ }
+ verify(monitor).failed(t);
+ verifyNoMoreInteractions(monitor);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void monitor_null() throws Exception {
+ new DelegateProducer<>(null, Futures.immediateFuture(42));
+ }
+
+ static final class DelegateProducer<T> extends AbstractProducer<T> {
+ private final ListenableFuture<T> delegate;
+
+ DelegateProducer(
+ Provider<ProductionComponentMonitor> componentMonitorProvider,
+ ListenableFuture<T> delegate) {
+ super(componentMonitorProvider, null);
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ListenableFuture<T> compute(ProducerMonitor unusedMonitor) {
+ return delegate;
+ }
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/ProducersTest.java b/producers/src/test/java/dagger/producers/internal/ProducersTest.java
new file mode 100644
index 0000000..e2707b3
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/ProducersTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link Producers}.
+ */
+@RunWith(JUnit4.class)
+public class ProducersTest {
+ @Test public void createFutureProduced_success() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFuture("monkey");
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isTrue();
+ assertThat(producedFuture.get().get()).isEqualTo("monkey");
+ }
+
+ @Test public void createFutureProduced_failure() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isTrue();
+ assertThat(getProducedException(producedFuture.get()).getCause()).hasMessage("monkey");
+ }
+
+ @Test public void createFutureProduced_cancelPropagatesBackwards() throws Exception {
+ ListenableFuture<String> future = SettableFuture.create();
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isFalse();
+ producedFuture.cancel(false);
+ assertThat(future.isCancelled()).isTrue();
+ }
+
+ @Test public void createFutureProduced_cancelDoesNotPropagateForwards() throws Exception {
+ ListenableFuture<String> future = SettableFuture.create();
+ ListenableFuture<Produced<String>> producedFuture = Producers.createFutureProduced(future);
+ assertThat(producedFuture.isDone()).isFalse();
+ future.cancel(false);
+ assertThat(producedFuture.isCancelled()).isFalse();
+ assertThat(getProducedException(producedFuture.get()).getCause())
+ .isInstanceOf(CancellationException.class);
+ }
+
+ private <T> ExecutionException getProducedException(Produced<T> produced) {
+ try {
+ produced.get();
+ throw new IllegalArgumentException("produced did not throw");
+ } catch (ExecutionException e) {
+ return e;
+ }
+ }
+
+ @Test public void createFutureSingletonSet_success() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFuture("monkey");
+ ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
+ assertThat(setFuture.isDone()).isTrue();
+ assertThat(setFuture.get()).containsExactly("monkey");
+ }
+
+ @Test public void createFutureSingletonSet_failure() throws Exception {
+ ListenableFuture<String> future = Futures.immediateFailedFuture(new RuntimeException("monkey"));
+ ListenableFuture<Set<String>> setFuture = Producers.createFutureSingletonSet(future);
+ assertThat(setFuture.isDone()).isTrue();
+ try {
+ setFuture.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).hasMessage("monkey");
+ }
+ }
+
+ @Test public void producerFromProvider() throws Exception {
+ Producer<Integer> producer = Producers.producerFromProvider(new Provider<Integer>() {
+ int i = 0;
+
+ @Override public Integer get() {
+ return i++;
+ }
+ });
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ assertThat(producer.get().get()).isEqualTo(0);
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/SetOfProducedProducerTest.java b/producers/src/test/java/dagger/producers/internal/SetOfProducedProducerTest.java
new file mode 100644
index 0000000..e36ba05
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/SetOfProducedProducerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Tests {@link SetOfProducedProducer}.
+ */
+@RunWith(JUnit4.class)
+public class SetOfProducedProducerTest {
+ @Test
+ public void success() throws Exception {
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)),
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(5, 7)));
+ assertThat(producer.get().get())
+ .containsExactly(
+ Produced.successful(1),
+ Produced.successful(2),
+ Produced.successful(5),
+ Produced.successful(7));
+ }
+
+ @Test
+ public void failure() throws Exception {
+ RuntimeException e = new RuntimeException("monkey");
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)),
+ Producers.<Set<Integer>>immediateFailedProducer(e));
+ assertThat(producer.get().get())
+ .containsExactly(
+ Produced.successful(1), Produced.successful(2), Produced.<Integer>failed(e));
+ }
+
+ @Test
+ public void delegateSetNpe() throws Exception {
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(Producers.<Set<Integer>>immediateProducer(null));
+ Results<Integer> results = Results.create(producer.get().get());
+ assertThat(results.successes).isEmpty();
+ assertThat(results.failures).hasSize(1);
+ assertThat(Iterables.getOnlyElement(results.failures).getCause())
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void oneOfDelegateSetNpe() throws Exception {
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(
+ Producers.<Set<Integer>>immediateProducer(null),
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(7, 3)));
+ Results<Integer> results = Results.create(producer.get().get());
+ assertThat(results.successes).containsExactly(3, 7);
+ assertThat(results.failures).hasSize(1);
+ assertThat(Iterables.getOnlyElement(results.failures).getCause())
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void delegateElementNpe() throws Exception {
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(
+ Producers.<Set<Integer>>immediateProducer(Collections.<Integer>singleton(null)));
+ Results<Integer> results = Results.create(producer.get().get());
+ assertThat(results.successes).isEmpty();
+ assertThat(results.failures).hasSize(1);
+ assertThat(Iterables.getOnlyElement(results.failures).getCause())
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void oneOfDelegateElementNpe() throws Exception {
+ Producer<Set<Produced<Integer>>> producer =
+ SetOfProducedProducer.create(
+ Producers.<Set<Integer>>immediateProducer(Sets.newHashSet(Arrays.asList(5, 2, null))));
+ Results<Integer> results = Results.create(producer.get().get());
+ assertThat(results.successes).containsExactly(2, 5);
+ assertThat(results.failures).hasSize(1);
+ assertThat(Iterables.getOnlyElement(results.failures).getCause())
+ .isInstanceOf(NullPointerException.class);
+ }
+
+ static final class Results<T> {
+ final ImmutableSet<T> successes;
+ final ImmutableSet<ExecutionException> failures;
+
+ private Results(ImmutableSet<T> successes, ImmutableSet<ExecutionException> failures) {
+ this.successes = successes;
+ this.failures = failures;
+ }
+
+ static <T> Results<T> create(Set<Produced<T>> setOfProduced) {
+ ImmutableSet.Builder<T> successes = ImmutableSet.builder();
+ ImmutableSet.Builder<ExecutionException> failures = ImmutableSet.builder();
+ for (Produced<T> produced : setOfProduced) {
+ try {
+ successes.add(produced.get());
+ } catch (ExecutionException e) {
+ failures.add(e);
+ }
+ }
+ return new Results<T>(successes.build(), failures.build());
+ }
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/internal/SetProducerTest.java b/producers/src/test/java/dagger/producers/internal/SetProducerTest.java
new file mode 100644
index 0000000..a38830f
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/internal/SetProducerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link SetProducer}.
+ */
+@RunWith(JUnit4.class)
+public class SetProducerTest {
+ @Test public void success() throws Exception {
+ Producer<Set<Integer>> producer =
+ SetProducer.create(
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)),
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(5, 7)));
+ assertThat(producer.get().get()).containsExactly(1, 2, 5, 7);
+ }
+
+ @Test public void delegateSetNpe() throws Exception {
+ Producer<Set<Integer>> producer =
+ SetProducer.create(
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)),
+ Producers.<Set<Integer>>immediateProducer(null));
+ ListenableFuture<Set<Integer>> future = producer.get();
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(NullPointerException.class);
+ }
+ }
+
+ @Test public void delegateElementNpe() throws Exception {
+ Producer<Set<Integer>> producer =
+ SetProducer.create(
+ Producers.<Set<Integer>>immediateProducer(ImmutableSet.of(1, 2)),
+ Producers.<Set<Integer>>immediateProducer(Collections.<Integer>singleton(null)));
+ ListenableFuture<Set<Integer>> future = producer.get();
+ try {
+ future.get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isInstanceOf(NullPointerException.class);
+ }
+ }
+}
diff --git a/producers/src/test/java/dagger/producers/monitoring/internal/MonitorsTest.java b/producers/src/test/java/dagger/producers/monitoring/internal/MonitorsTest.java
new file mode 100644
index 0000000..e7f4274
--- /dev/null
+++ b/producers/src/test/java/dagger/producers/monitoring/internal/MonitorsTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.monitoring.internal;
+
+import com.google.common.collect.ImmutableList;
+import dagger.producers.monitoring.ProducerMonitor;
+import dagger.producers.monitoring.ProducerToken;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(JUnit4.class)
+public final class MonitorsTest {
+ @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactory;
+ @Mock private ProductionComponentMonitor mockProductionComponentMonitor;
+ @Mock private ProducerMonitor mockProducerMonitor;
+ @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryA;
+ @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryB;
+ @Mock private ProductionComponentMonitor.Factory mockProductionComponentMonitorFactoryC;
+ @Mock private ProductionComponentMonitor mockProductionComponentMonitorA;
+ @Mock private ProductionComponentMonitor mockProductionComponentMonitorB;
+ @Mock private ProductionComponentMonitor mockProductionComponentMonitorC;
+ @Mock private ProducerMonitor mockProducerMonitorA;
+ @Mock private ProducerMonitor mockProducerMonitorB;
+ @Mock private ProducerMonitor mockProducerMonitorC;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void zeroMonitorsReturnsNoOp() {
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.<ProductionComponentMonitor.Factory>of());
+ assertThat(factory).isSameAs(Monitors.noOpProductionComponentMonitorFactory());
+ }
+
+ @Test
+ public void singleMonitor_nullProductionComponentMonitor() {
+ when(mockProductionComponentMonitorFactory.create(any(Object.class))).thenReturn(null);
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ assertThat(factory.create(new Object())).isSameAs(Monitors.noOpProductionComponentMonitor());
+ }
+
+ @Test
+ public void singleMonitor_throwingProductionComponentMonitorFactory() {
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactory)
+ .create(any(Object.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ assertThat(factory.create(new Object())).isSameAs(Monitors.noOpProductionComponentMonitor());
+ }
+
+ @Test
+ public void singleMonitor_nullProducerMonitor() {
+ when(mockProductionComponentMonitorFactory.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitor);
+ when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(null);
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ assertThat(monitor.producerMonitorFor(ProducerToken.create(Object.class)))
+ .isSameAs(Monitors.noOpProducerMonitor());
+ }
+
+ @Test
+ public void singleMonitor_throwingProductionComponentMonitor() {
+ when(mockProductionComponentMonitorFactory.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitor);
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitor)
+ .producerMonitorFor(any(ProducerToken.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ assertThat(monitor.producerMonitorFor(ProducerToken.create(Object.class)))
+ .isSameAs(Monitors.noOpProducerMonitor());
+ }
+
+ @Test
+ public void singleMonitor_normalProducerMonitorSuccess() {
+ setUpNormalSingleMonitor();
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitor);
+ order.verify(mockProducerMonitor).methodStarting();
+ order.verify(mockProducerMonitor).methodFinished();
+ order.verify(mockProducerMonitor).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitor);
+ }
+
+ @Test
+ public void singleMonitor_normalProducerMonitorFailure() {
+ setUpNormalSingleMonitor();
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+ Throwable t = new RuntimeException("monkey");
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.failed(t);
+
+ InOrder order = inOrder(mockProducerMonitor);
+ order.verify(mockProducerMonitor).methodStarting();
+ order.verify(mockProducerMonitor).methodFinished();
+ order.verify(mockProducerMonitor).failed(t);
+ verifyNoMoreInteractions(mockProducerMonitor);
+ }
+
+ @Test
+ public void singleMonitor_throwingProducerMonitorSuccess() {
+ setUpNormalSingleMonitor();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodStarting();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodFinished();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).succeeded(any(Object.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitor);
+ order.verify(mockProducerMonitor).methodStarting();
+ order.verify(mockProducerMonitor).methodFinished();
+ order.verify(mockProducerMonitor).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitor);
+ }
+
+ @Test
+ public void singleMonitor_throwingProducerMonitorFailure() {
+ setUpNormalSingleMonitor();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodStarting();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodFinished();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).failed(any(Throwable.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(mockProductionComponentMonitorFactory));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+ Throwable t = new RuntimeException("gorilla");
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.failed(t);
+
+ InOrder order = inOrder(mockProducerMonitor);
+ order.verify(mockProducerMonitor).methodStarting();
+ order.verify(mockProducerMonitor).methodFinished();
+ order.verify(mockProducerMonitor).failed(t);
+ verifyNoMoreInteractions(mockProducerMonitor);
+ }
+
+ @Test
+ public void multipleMonitors_nullProductionComponentMonitors() {
+ when(mockProductionComponentMonitorFactoryA.create(any(Object.class))).thenReturn(null);
+ when(mockProductionComponentMonitorFactoryB.create(any(Object.class))).thenReturn(null);
+ when(mockProductionComponentMonitorFactoryC.create(any(Object.class))).thenReturn(null);
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ assertThat(factory.create(new Object())).isSameAs(Monitors.noOpProductionComponentMonitor());
+ }
+
+ @Test
+ public void multipleMonitors_throwingProductionComponentMonitorFactories() {
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactoryA)
+ .create(any(Object.class));
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactoryB)
+ .create(any(Object.class));
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactoryC)
+ .create(any(Object.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ assertThat(factory.create(new Object())).isSameAs(Monitors.noOpProductionComponentMonitor());
+ }
+
+ @Test
+ public void multipleMonitors_someNullProductionComponentMonitors() {
+ when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitorA);
+ when(mockProductionComponentMonitorFactoryB.create(any(Object.class))).thenReturn(null);
+ when(mockProductionComponentMonitorFactoryC.create(any(Object.class))).thenReturn(null);
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitorA);
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitorA);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorA).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitorA);
+ }
+
+ @Test
+ public void multipleMonitors_someThrowingProductionComponentMonitorFactories() {
+ when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitorA);
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactoryB)
+ .create(any(Object.class));
+ doThrow(new RuntimeException("monkey"))
+ .when(mockProductionComponentMonitorFactoryC)
+ .create(any(Object.class));
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitorA);
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitorA);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorA).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitorA);
+ }
+
+ @Test
+ public void multipleMonitors_normalProductionComponentMonitorSuccess() {
+ setUpNormalMultipleMonitors();
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorB).methodStarting();
+ order.verify(mockProducerMonitorC).methodStarting();
+ order.verify(mockProducerMonitorC).methodFinished();
+ order.verify(mockProducerMonitorB).methodFinished();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorC).succeeded(o);
+ order.verify(mockProducerMonitorB).succeeded(o);
+ order.verify(mockProducerMonitorA).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ }
+
+ @Test
+ public void multipleMonitors_normalProductionComponentMonitorFailure() {
+ setUpNormalMultipleMonitors();
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Throwable t = new RuntimeException("chimpanzee");
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.failed(t);
+
+ InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorB).methodStarting();
+ order.verify(mockProducerMonitorC).methodStarting();
+ order.verify(mockProducerMonitorC).methodFinished();
+ order.verify(mockProducerMonitorB).methodFinished();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorC).failed(t);
+ order.verify(mockProducerMonitorB).failed(t);
+ order.verify(mockProducerMonitorA).failed(t);
+ verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ }
+
+ @Test
+ public void multipleMonitors_someThrowingProducerMonitorsSuccess() {
+ setUpNormalMultipleMonitors();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).methodStarting();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorB).methodFinished();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorC).succeeded(any(Object.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Object o = new Object();
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.succeeded(o);
+
+ InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorB).methodStarting();
+ order.verify(mockProducerMonitorC).methodStarting();
+ order.verify(mockProducerMonitorC).methodFinished();
+ order.verify(mockProducerMonitorB).methodFinished();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorC).succeeded(o);
+ order.verify(mockProducerMonitorB).succeeded(o);
+ order.verify(mockProducerMonitorA).succeeded(o);
+ verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ }
+
+ @Test
+ public void multipleMonitors_someThrowingProducerMonitorsFailure() {
+ setUpNormalMultipleMonitors();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).methodStarting();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorB).methodFinished();
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorC).failed(any(Throwable.class));
+ ProductionComponentMonitor.Factory factory =
+ Monitors.delegatingProductionComponentMonitorFactory(
+ ImmutableList.of(
+ mockProductionComponentMonitorFactoryA,
+ mockProductionComponentMonitorFactoryB,
+ mockProductionComponentMonitorFactoryC));
+ ProductionComponentMonitor monitor = factory.create(new Object());
+ ProducerMonitor producerMonitor =
+ monitor.producerMonitorFor(ProducerToken.create(Object.class));
+
+ Throwable t = new RuntimeException("chimpanzee");
+ producerMonitor.methodStarting();
+ producerMonitor.methodFinished();
+ producerMonitor.failed(t);
+
+ InOrder order = inOrder(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ order.verify(mockProducerMonitorA).methodStarting();
+ order.verify(mockProducerMonitorB).methodStarting();
+ order.verify(mockProducerMonitorC).methodStarting();
+ order.verify(mockProducerMonitorC).methodFinished();
+ order.verify(mockProducerMonitorB).methodFinished();
+ order.verify(mockProducerMonitorA).methodFinished();
+ order.verify(mockProducerMonitorC).failed(t);
+ order.verify(mockProducerMonitorB).failed(t);
+ order.verify(mockProducerMonitorA).failed(t);
+ verifyNoMoreInteractions(mockProducerMonitorA, mockProducerMonitorB, mockProducerMonitorC);
+ }
+
+ private void setUpNormalSingleMonitor() {
+ when(mockProductionComponentMonitorFactory.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitor);
+ when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitor);
+ }
+
+ private void setUpNormalMultipleMonitors() {
+ when(mockProductionComponentMonitorFactoryA.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitorA);
+ when(mockProductionComponentMonitorFactoryB.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitorB);
+ when(mockProductionComponentMonitorFactoryC.create(any(Object.class)))
+ .thenReturn(mockProductionComponentMonitorC);
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitorA);
+ when(mockProductionComponentMonitorB.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitorB);
+ when(mockProductionComponentMonitorC.producerMonitorFor(any(ProducerToken.class)))
+ .thenReturn(mockProducerMonitorC);
+ }
+}
diff --git a/test_defs.bzl b/test_defs.bzl
deleted file mode 100644
index 15ab299..0000000
--- a/test_defs.bzl
+++ /dev/null
@@ -1,195 +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.
-
-
-# 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(user): split into two functions for functional vs non-functional tests?
-def GenJavaTests(
- name,
- srcs,
- deps,
- test_only_deps = None,
- plugins = None,
- javacopts = None,
- lib_javacopts = None,
- test_javacopts = None,
- functional = True):
- _GenTests(
- native.java_library,
- native.java_test,
- name,
- srcs,
- deps,
- test_only_deps,
- plugins,
- javacopts,
- lib_javacopts,
- test_javacopts,
- functional,
- )
-
-def GenRobolectricTests(
- name,
- srcs,
- deps,
- test_only_deps = None,
- plugins = None,
- javacopts = None,
- lib_javacopts = None,
- test_javacopts = None,
- functional = True,
- manifest_values = None):
- # TODO(ronshapiro): enable these with these instructions:
- # https://docs.bazel.build/versions/master/be/android.html#android_local_test_examples
- # We probably want to import all of Robolectric's dependencies into bazel-common because there
- # are some differences (i.e. we both provide Guava).
- pass
-
-def _GenTests(
- library_rule_type,
- test_rule_type,
- name,
- srcs,
- deps,
- test_only_deps = None,
- plugins = None,
- javacopts = None,
- lib_javacopts = None,
- test_javacopts = None,
- functional = True,
- test_kwargs = {}):
- _gen_tests(
- library_rule_type,
- test_rule_type,
- name,
- srcs,
- deps,
- test_only_deps,
- plugins,
- javacopts,
- lib_javacopts,
- test_javacopts,
- functional,
- test_kwargs = test_kwargs,
- )
-
- if functional:
- for (variant_name, extra_javacopts) in BUILD_VARIANTS.items():
- variant_javacopts = (javacopts or []) + extra_javacopts
- _gen_tests(
- library_rule_type,
- test_rule_type,
- name,
- srcs,
- deps,
- test_only_deps,
- plugins,
- variant_javacopts,
- lib_javacopts,
- test_javacopts,
- functional,
- variant_name,
- test_kwargs = test_kwargs,
- )
-
-def _gen_tests(
- library_rule_type,
- test_rule_type,
- name,
- srcs,
- deps,
- test_only_deps,
- plugins,
- javacopts,
- lib_javacopts,
- test_javacopts,
- functional,
- variant_name = None,
- test_kwargs = {}):
- if variant_name:
- suffix = "_" + variant_name
- tags = [variant_name]
-
- # Add jvm_flags so that the mode can be accessed from within tests.
- jvm_flags = ["-Ddagger.mode=" + variant_name]
- else:
- suffix = ""
- tags = []
- jvm_flags = []
-
- test_files = []
- supporting_files = []
-
- for src in srcs:
- if src.endswith("Test.java"):
- test_files.append(src)
- else:
- supporting_files.append(src)
-
- if not test_only_deps:
- test_only_deps = []
-
- test_deps = test_only_deps + deps
- if supporting_files:
- supporting_files_name = name + suffix + "_lib"
- test_deps.append(":" + supporting_files_name)
- library_rule_type(
- name = supporting_files_name,
- testonly = 1,
- srcs = supporting_files,
- javacopts = (javacopts or []) + (lib_javacopts or []),
- plugins = plugins,
- tags = tags,
- deps = deps,
- )
- if functional:
- _hjar_test(supporting_files_name, tags)
-
- for test_file in test_files:
- test_name = test_file.replace(".java", "")
- prefix_path = "src/test/java/"
- package_name = native.package_name()
- if package_name.find("javatests/") != -1:
- prefix_path = "javatests/"
- test_class = (package_name + "/" + test_name).rpartition(prefix_path)[2].replace("/", ".")
- test_rule_type(
- name = test_name + suffix,
- srcs = [test_file],
- javacopts = (javacopts or []) + (test_javacopts or []),
- jvm_flags = jvm_flags,
- plugins = plugins,
- tags = tags,
- test_class = test_class,
- deps = test_deps,
- **test_kwargs
- )
-
-
-def _hjar_test(name, tags):
- pass
diff --git a/tools/BUILD b/tools/BUILD
deleted file mode 100644
index 7b3cc6c..0000000
--- a/tools/BUILD
+++ /dev/null
@@ -1,22 +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:
-# Tools for Dagger
-
-package(default_visibility = ["//:src"])
-
-exports_files([
- "pom-template.xml",
-])
diff --git a/tools/maven.bzl b/tools/maven.bzl
deleted file mode 100644
index 2ac0359..0000000
--- a/tools/maven.bzl
+++ /dev/null
@@ -1,38 +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.
-
-"""Macros to simplify generating maven files.
-"""
-
-load("@google_bazel_common//tools/maven:pom_file.bzl", default_pom_file = "pom_file")
-
-def pom_file(name, targets, artifact_name, artifact_id, packaging = None, **kwargs):
- default_pom_file(
- name = name,
- targets = targets,
- preferred_group_ids = [
- "com.google.dagger",
- "com.google",
- ],
- template_file = "//tools:pom-template.xml",
- substitutions = {
- "{artifact_name}": artifact_name,
- "{artifact_id}": artifact_id,
- "{packaging}": packaging or "jar",
- },
- excluded_artifacts = ["com.google.auto:auto-common"],
- **kwargs
- )
-
-POM_VERSION = "2.23.1"
diff --git a/tools/pom-template.xml b/tools/pom-template.xml
deleted file mode 100644
index 39ed62d..0000000
--- a/tools/pom-template.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- 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.
--->
-<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>7</version>
- </parent>
-
- <groupId>com.google.dagger</groupId>
- <artifactId>{artifact_id}</artifactId>
- <name>{artifact_name}</name>
- <version>{pom_version}</version>
- <description>A fast dependency injector for Android and Java.</description>
- <url>https://github.com/google/dagger</url>
- <packaging>{packaging}</packaging>
-
- <scm>
- <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>
- </scm>
-
- <issueManagement>
- <system>GitHub Issues</system>
- <url>http://github.com/google/dagger/issues</url>
- </issueManagement>
-
- <licenses>
- <license>
- <name>Apache 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- </license>
- </licenses>
-
- <organization>
- <name>Google, Inc.</name>
- <url>http://www.google.com</url>
- </organization>
-
- <dependencies>
-{generated_bzl_deps}
- </dependencies>
-</project>
diff --git a/util/deploy-to-maven-central.sh b/util/deploy-to-maven-central.sh
deleted file mode 100755
index 1f721a1..0000000
--- a/util/deploy-to-maven-central.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-if [ $# -lt 2 ]; then
- echo "usage $0 <ssl-key> <version-name> [<param> ...]"
- exit 1;
-fi
-key=$1
-version_name=$2
-shift 2
-
-if [[ ! "$version_name" =~ ^2\. ]]; then
- echo 'Version name must begin with "2."'
- exit 2
-fi
-
-if [[ "$version_name" =~ " " ]]; then
- echo "Version name must not have any spaces"
- exit 3
-fi
-
-bazel test //...
-
-bash $(dirname $0)/execute-deploy.sh \
- "gpg:sign-and-deploy-file" \
- "$version_name" \
- "-DrepositoryId=sonatype-nexus-staging" \
- "-Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/" \
- "-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"
-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
deleted file mode 100755
index 1153468..0000000
--- a/util/execute-deploy.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/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/generate-latest-docs.sh b/util/generate-latest-docs.sh
index 8e9304c..b68df0c 100755
--- a/util/generate-latest-docs.sh
+++ b/util/generate-latest-docs.sh
@@ -1,30 +1,25 @@
# see http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/ for details
-set -eu
-
if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
- [ "$TRAVIS_JDK_VERSION" == "$JDK_FOR_PUBLISHING" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "oraclejdk7" ] && \
[ "$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"
+ mvn javadoc:aggregate -P!examples
+ TARGET="$(pwd)/target"
cd $HOME
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 "travis@travis-ci.org"
git config --global user.name "travis-ci"
- git rm -rf api/latest
+ git rm -rf api/latest
mkdir -p api
- unzip "$JAVADOC_JAR" -d api/latest
- rm -rf api/latest/META-INF/
+ mv ${TARGET}/site/apidocs api/latest
git add -f api/latest
- git commit -m "Latest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages"
+ git commit -m "Lastest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages"
git push -fq origin gh-pages > /dev/null
echo -e "Published Javadoc to gh-pages.\n"
-else
- 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
deleted file mode 100755
index 8f77a41..0000000
--- a/util/install-local-snapshot.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-echo -e "Installing maven snapshot locally...\n"
-
-bash $(dirname $0)/execute-deploy.sh \
- "install:install-file" \
- "LOCAL-SNAPSHOT"
-
-echo -e "Installed local snapshot"
diff --git a/util/mvn-deploy.sh b/util/mvn-deploy.sh
new file mode 100755
index 0000000..ec4b7a0
--- /dev/null
+++ b/util/mvn-deploy.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+if [ $# -lt 1 ]; then
+ echo "usage $0 <ssl-key> [<param> ...]"
+ exit 1;
+fi
+key=$1
+shift
+
+#validate key
+keystatus=$(gpg --list-keys | grep ${key} | awk '{print $1}')
+if [ "${keystatus}" != "pub" ]; then
+ echo "Could not find public key with label ${key}"
+ echo -n "Available keys from: "
+ gpg --list-keys | grep --invert-match '^sub'
+
+ exit 64
+fi
+
+mvn "$@" -P '!examples' -P sonatype-oss-release \
+ -Dgpg.skip=false -Dgpg.keyname=${key} \
+ clean site:jar deploy
diff --git a/util/publish-snapshot-on-commit.sh b/util/publish-snapshot-on-commit.sh
index 944a2c3..be27cb6 100755
--- a/util/publish-snapshot-on-commit.sh
+++ b/util/publish-snapshot-on-commit.sh
@@ -1,21 +1,12 @@
# see https://coderwall.com/p/9b_lfq
-set -eu
-
if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
- [ "$TRAVIS_JDK_VERSION" == "$JDK_FOR_PUBLISHING" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "oraclejdk7" ] && \
[ "$TRAVIS_PULL_REQUEST" == "false" ] && \
[ "$TRAVIS_BRANCH" == "master" ]; then
echo -e "Publishing maven snapshot...\n"
- bash $(dirname $0)/execute-deploy.sh \
- "deploy:deploy-file" \
- "HEAD-SNAPSHOT" \
- "-DrepositoryId=sonatype-nexus-snapshots" \
- "-Durl=https://oss.sonatype.org/content/repositories/snapshots" \
- "--settings=$(dirname $0)/settings.xml"
+ mvn clean source:jar deploy --settings="util/settings.xml" -DskipTests=true -Dinvoker.skip=true -Dmaven.javadoc.skip=true
echo -e "Published maven snapshot"
-else
- echo -e "Not publishing snapshot for jdk=${TRAVIS_JDK_VERSION} and branch=${TRAVIS_BRANCH}"
fi