From 842d282b6a44889290e2bf44acaf80e2e8b41ea8 Mon Sep 17 00:00:00 2001 From: sameb Date: Mon, 30 Mar 2015 11:33:58 -0700 Subject: [PATCH 01/16] Fix members injection type argument validation to allow arrays. Also improve the error message to tell you the dependency path that led to the invalid type. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=89884806 --- .../ChildOfArrayOfParentOfStringArray.java | 20 ++++++ .../ChildOfPrimitiveIntArray.java | 20 ++++++ .../membersinject/ChildOfStringArray.java | 20 ++++++ .../membersinject/MembersInjectComponent.java | 27 ++++++++ .../MembersInjectGenericParent.java | 24 +++++++ .../membersinject/MembersInjectModule.java | 31 +++++++++ .../test/membersinject/MembersInjectTest.java | 45 +++++++++++++ .../codegen/BindingGraphValidator.java | 65 +++++++++++++++++-- .../internal/codegen/ErrorMessages.java | 4 +- 9 files changed, 248 insertions(+), 8 deletions(-) create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfArrayOfParentOfStringArray.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfPrimitiveIntArray.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/ChildOfStringArray.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectComponent.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectGenericParent.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/membersinject/MembersInjectModule.java create mode 100644 compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.java 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 00000000000..22efcf12ed5 --- /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[]> { +} 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 00000000000..e01c1c266f6 --- /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 { + +} 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 00000000000..8ec943b963b --- /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 { + +} 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 00000000000..9ab8c1928a4 --- /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 00000000000..064b8864210 --- /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 { + + @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 00000000000..a6c1fadb9b1 --- /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[] provideFooArrayOfStringArray() { return new MembersInjectGenericParent[10]; } + +} 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 00000000000..3b1127df530 --- /dev/null +++ b/compiler/src/it/functional-tests/src/test/java/test/membersinject/MembersInjectTest.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.membersinject; + +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 = Dagger_MembersInjectComponent.builder().build(); + + ChildOfStringArray childOfStringArray = new ChildOfStringArray(); + component.inject(childOfStringArray); + } + + @Test public void testMembersInject_nestedArrays() { + MembersInjectComponent component = Dagger_MembersInjectComponent.builder().build(); + + ChildOfArrayOfParentOfStringArray childOfArrayOfParentOfStringArray = + new ChildOfArrayOfParentOfStringArray(); + component.inject(childOfArrayOfParentOfStringArray); + } + + @Test public void testMembersInject_primitives() { + MembersInjectComponent component = Dagger_MembersInjectComponent.builder().build(); + + ChildOfPrimitiveIntArray childOfPrimitiveIntArray = new ChildOfPrimitiveIntArray(); + component.inject(childOfPrimitiveIntArray); + } +} diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java index 6d1827a1116..7f9263a686e 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java @@ -48,8 +48,9 @@ import javax.lang.model.element.AnnotationMirror; 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.TypeKind; +import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleTypeVisitor6; import javax.lang.model.util.Types; @@ -274,11 +275,55 @@ private boolean validateMembersInjectionBinding(MembersInjectionBinding binding, @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. + // resolve that to actual types. If the arg was an array, validate the type + // of the array. for (TypeMirror arg : type.getTypeArguments()) { - if (arg.getKind() != TypeKind.DECLARED) { - reportBuilder.addItem(MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE, - path.peek().request().requestElement()); + boolean declared; + switch (arg.getKind()) { + case ARRAY: + declared = MoreTypes.asArray(arg).getComponentType().accept( + new SimpleTypeVisitor6() { + @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 printableDependencyPath = FluentIterable.from(path) + .transform(REQUEST_FROM_RESOLVED_REQUEST) + .transform(dependencyRequestFormatter) + .filter(Predicates.not(Predicates.equalTo(""))) + .toList() + .reverse(); + reportBuilder.addItem( + String.format(MEMBERS_INJECTION_WITH_UNBOUNDED_TYPE, + arg.toString(), + type.toString(), + Joiner.on('\n').join(printableDependencyPath)), + path.peek().request().requestElement()); return false; } } @@ -290,8 +335,16 @@ private boolean validateMembersInjectionBinding(MembersInjectionBinding binding, // 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 printableDependencyPath = FluentIterable.from(path) + .transform(REQUEST_FROM_RESOLVED_REQUEST) + .transform(dependencyRequestFormatter) + .filter(Predicates.not(Predicates.equalTo(""))) + .toList() + .reverse(); reportBuilder.addItem( - String.format(ErrorMessages.MEMBERS_INJECTION_WITH_RAW_TYPE, type.toString()), + String.format(ErrorMessages.MEMBERS_INJECTION_WITH_RAW_TYPE, + type.toString(), + Joiner.on('\n').join(printableDependencyPath)), path.peek().request().requestElement()); return false; } diff --git a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java index e5b657bee64..8604eee34f5 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java +++ b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java @@ -195,10 +195,10 @@ final class ErrorMessages { "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."; + "%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."; + "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"; From 78ac368f3b019d71d323e7793fb6330cc7d8ae47 Mon Sep 17 00:00:00 2001 From: gak Date: Mon, 30 Mar 2015 15:48:00 -0700 Subject: [PATCH 02/16] A major update to subcomponents: * Add validation for subcomponent factory methods. Malformed methods will get flagged with (hopefully) helpful error messages. * Add some friendly error messages for component methods as well. * Allow subcomponent factory methods to accept modules, particularly modules without default constructors. Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=89910213 --- .../ChildComponentRequiringModules.java | 26 +++ .../ChildModuleWithParameters.java | 26 +++ .../subcomponent/ChildModuleWithState.java | 32 +++ .../test/subcomponent/ParentComponent.java | 4 + ...ntScopeTest.java => SubcomponentTest.java} | 18 +- .../dagger/internal/codegen/BindingGraph.java | 45 +++- .../codegen/BindingGraphValidator.java | 43 ++-- .../internal/codegen/ComponentGenerator.java | 204 +++++++++--------- .../internal/codegen/ComponentProcessor.java | 10 +- .../internal/codegen/ComponentValidator.java | 157 +++++++++++++- .../codegen/ConfigurationAnnotations.java | 22 +- .../internal/codegen/ErrorMessages.java | 2 +- .../java/dagger/internal/codegen/Util.java | 55 +++++ .../codegen/SubcomponentValidationTest.java | 195 +++++++++++++++++ 14 files changed, 698 insertions(+), 141 deletions(-) create mode 100644 compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildComponentRequiringModules.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java create mode 100644 compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithState.java rename compiler/src/it/functional-tests/src/test/java/test/subcomponent/{SubcomponentScopeTest.java => SubcomponentTest.java} (81%) create mode 100644 compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java 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 00000000000..905c68990d3 --- /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/ChildModuleWithParameters.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ChildModuleWithParameters.java new file mode 100644 index 00000000000..e18b4a6da7e --- /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 00000000000..5908a005ba5 --- /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/ParentComponent.java b/compiler/src/it/functional-tests/src/main/java/test/subcomponent/ParentComponent.java index ed4e6f0e809..babf3ea344d 100644 --- 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 @@ -28,4 +28,8 @@ interface ParentComponent { Set objectSet(); ChildComponent newChildComponent(); + + ChildComponentRequiringModules newChildComponentRequiringModules( + ChildModuleWithParameters cmwp, + ChildModuleWithState childModuleWithState); } diff --git a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentScopeTest.java b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java similarity index 81% rename from compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentScopeTest.java rename to compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java index 4e897ff72fa..69fff735e53 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentScopeTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/subcomponent/SubcomponentTest.java @@ -24,7 +24,7 @@ import static com.google.common.truth.Truth.assertThat; @RunWith(JUnit4.class) -public class SubcomponentScopeTest { +public class SubcomponentTest { @Test public void scopePropagatesUpward_class() { ParentComponent parentComponent = Dagger_ParentComponent.create(); @@ -73,4 +73,20 @@ public void unscopedProviders() { .newGrandchildComponent() .getUnscopedTypeProvider()); } + + @Test + public void passedModules() { + ParentComponent parentComponent = Dagger_ParentComponent.create(); + 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); + } } diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java index c2f8adf065e..a2926cc22d2 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java @@ -55,6 +55,7 @@ import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules; import static dagger.internal.codegen.MembersInjectionBinding.Strategy.DELEGATE; import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP; +import static dagger.internal.codegen.Util.componentCanMakeNewInstances; import static javax.lang.model.util.ElementFilter.methodsIn; /** @@ -64,9 +65,14 @@ */ @AutoValue abstract class BindingGraph { + enum ModuleStrategy { + PASSED, + CONSTRUCTED, + } + abstract ComponentDescriptor componentDescriptor(); abstract ImmutableSet entryPoints(); - abstract ImmutableMap> transitiveModules(); + abstract ImmutableMap transitiveModules(); abstract ImmutableMap resolvedBindings(); abstract ImmutableMap subgraphs(); @@ -191,9 +197,13 @@ && isComponentProductionMethod(elements, method)) { ImmutableSet moduleTypes = MoreTypes.asTypeElements(getComponentModules(componentAnnotation)); - ImmutableMap> transitiveModules = - getTransitiveModules(types, elements, moduleTypes); - for (TypeElement module : transitiveModules.keySet()) { + ImmutableMap.Builder transitiveModules = ImmutableMap.builder(); + for (TypeElement module : getTransitiveModules(types, elements, moduleTypes)) { + transitiveModules.put(module, + (componentCanMakeNewInstances(module) && module.getTypeParameters().isEmpty()) + ? ModuleStrategy.CONSTRUCTED + : ModuleStrategy.PASSED); + // traverse the modules, collect the bindings List moduleMethods = methodsIn(elements.getAllMembers(module)); for (ExecutableElement moduleMethod : moduleMethods) { @@ -233,8 +243,8 @@ && isComponentProductionMethod(elements, method)) { return new AutoValue_BindingGraph( componentDescriptor, componentMethodRequests, - transitiveModules, - ImmutableMap.copyOf(requestResolver.resolvedBindings), + transitiveModules.build(), + requestResolver.getResolvedBindings(), subgraphsBuilder.build()); } @@ -483,6 +493,29 @@ void resolve(DependencyRequest request) { cycleStack.pop(); } } + + ImmutableMap getResolvedBindings() { + ImmutableMap.Builder resolvedBindingsBuilder = + ImmutableMap.builder(); + resolvedBindingsBuilder.putAll(resolvedBindings); + if (parentResolver.isPresent()) { + for (ResolvedBindings resolvedInParent : + parentResolver.get().getResolvedBindings().values()) { + BindingKey bindingKey = resolvedInParent.bindingKey(); + if (!resolvedBindings.containsKey(bindingKey)) { + if (resolvedInParent.ownedBindings().isEmpty()) { + // reuse the instance if we can get away with it + resolvedBindingsBuilder.put(bindingKey, resolvedInParent); + } else { + resolvedBindingsBuilder.put(bindingKey, + ResolvedBindings.create( + bindingKey, ImmutableSet.of(), resolvedInParent.bindings())); + } + } + } + } + return resolvedBindingsBuilder.build(); + } } } } diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java index 7f9263a686e..8e3022e2bb7 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java @@ -43,6 +43,7 @@ import java.util.Formatter; import java.util.HashSet; import java.util.Iterator; +import java.util.Map.Entry; import java.util.Set; import javax.inject.Singleton; import javax.lang.model.element.AnnotationMirror; @@ -107,6 +108,11 @@ public class BindingGraphValidator implements Validator { public ValidationReport validate(final BindingGraph subject) { final ValidationReport.Builder reportBuilder = ValidationReport.Builder.about(subject); + return validate(subject, reportBuilder); + } + + private ValidationReport validate(final BindingGraph subject, + final ValidationReport.Builder reportBuilder) { ImmutableMap resolvedBindings = subject.resolvedBindings(); validateComponentScope(subject, reportBuilder, resolvedBindings); @@ -137,9 +143,18 @@ boolean visitResolvedRequest(Deque path) { }); } + validateSubcomponents(subject, reportBuilder); + return reportBuilder.build(); } + private void validateSubcomponents(BindingGraph graph, + ValidationReport.Builder reportBuilder) { + for (Entry subgraphEntry : graph.subgraphs().entrySet()) { + validate(subgraphEntry.getValue(), reportBuilder); + } + } + /** * Validates that the set of bindings resolved is consistent with the type of the binding, and * returns true if the bindings are valid. @@ -502,7 +517,7 @@ void validateComponentScope(final BindingGraph subject, ImmutableSet.Builder incompatiblyScopedMethodsBuilder = ImmutableSet.builder(); for (ResolvedBindings bindings : resolvedBindings.values()) { if (bindings.bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)) { - for (ContributionBinding contributionBinding : bindings.contributionBindings()) { + for (ContributionBinding contributionBinding : bindings.ownedContributionBindings()) { if (contributionBinding instanceof ProvisionBinding) { ProvisionBinding provisionBinding = (ProvisionBinding) contributionBinding; if (provisionBinding.scope().isPresent() @@ -576,16 +591,13 @@ private void reportMissingBinding( boolean requiresContributionMethod = !key.isValidImplicitProvisionKey(types); boolean requiresProvision = doesPathRequireProvisionOnly(path); StringBuilder errorMessage = new StringBuilder(); - final String requiresErrorMessageFormat; - if (requiresContributionMethod) { - requiresErrorMessageFormat = requiresProvision - ? REQUIRES_PROVIDER_FORMAT - : REQUIRES_PROVIDER_OR_PRODUCER_FORMAT; - } else { - requiresErrorMessageFormat = requiresProvision - ? REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_FORMAT - : REQUIRES_AT_INJECT_CONSTRUCTOR_OR_PROVIDER_OR_PRODUCER_FORMAT; - } + 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, typeName)); if (key.isValidMembersInjectionKey() && !injectBindingRegistry.getOrFindMembersInjectionBinding(key).injectionSites() @@ -750,8 +762,13 @@ abstract static class ResolvedRequest { abstract ResolvedBindings binding(); static ResolvedRequest create(DependencyRequest request, BindingGraph graph) { - return new AutoValue_BindingGraphValidator_ResolvedRequest( - request, graph.resolvedBindings().get(request.bindingKey())); + BindingKey bindingKey = request.bindingKey(); + ResolvedBindings resolvedBindings = graph.resolvedBindings().get(bindingKey); + return new AutoValue_BindingGraphValidator_ResolvedRequest(request, + resolvedBindings == null + ? ResolvedBindings.create(bindingKey, + ImmutableSet.of(), ImmutableSet.of()) + : resolvedBindings); } } diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index 678b72c93ea..72540b0bf9a 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -33,6 +33,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.collect.Sets.SetView; import com.google.common.util.concurrent.ListenableFuture; import dagger.Component; import dagger.MapKey; @@ -89,6 +90,7 @@ import static com.google.auto.common.MoreTypes.asDeclared; import static com.google.common.base.CaseFormat.LOWER_CAMEL; +import static com.google.common.base.Verify.verify; import static dagger.internal.codegen.Binding.bindingPackageFor; import static dagger.internal.codegen.ConfigurationAnnotations.getMapKeys; import static dagger.internal.codegen.ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_COMPONENT_METHOD; @@ -99,13 +101,11 @@ import static dagger.internal.codegen.SourceFiles.factoryNameForProvisionBinding; import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement; import static dagger.internal.codegen.SourceFiles.membersInjectorNameForMembersInjectionBinding; -import static javax.lang.model.element.ElementKind.CONSTRUCTOR; +import static dagger.internal.codegen.Util.componentCanMakeNewInstances; 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.element.NestingKind.MEMBER; -import static javax.lang.model.element.NestingKind.TOP_LEVEL; import static javax.lang.model.type.TypeKind.VOID; /** @@ -272,7 +272,7 @@ private ImmutableMap writeComponent( .addSnippet("}") .addSnippet("this.%s = %s;", builderField.name(), contributionName) .addSnippet("return this;"); - if (hasNoArgsConstructor(contributionElement)) { + if (componentCanMakeNewInstances(contributionElement)) { buildMethod.body() .addSnippet("if (%s == null) {", builderField.name()) .addSnippet(" this.%s = new %s();", @@ -329,88 +329,99 @@ private ImmutableMap writeComponent( writeInterfaceMethods(input, componentWriter, memberSelectSnippets, enumBindingKeys); - writeSubcomponents(input, - componentWriter, - proxyWriters, - componentContributionFields, - memberSelectSnippets, - multibindingContributionSnippets); + for (Entry subgraphEntry : input.subgraphs().entrySet()) { + writeSubcomponent(componentWriter, + proxyWriters, + componentContributionFields, + memberSelectSnippets, + multibindingContributionSnippets, + subgraphEntry.getKey(), + subgraphEntry.getValue()); + } return memberSelectSnippets; } - private void writeSubcomponents(BindingGraph input, - ClassWriter componentWriter, + private void writeSubcomponent(ClassWriter componentWriter, Set proxyWriters, - Map componentContributionFields, + Map parentContributionFields, ImmutableMap parentMemberSelectSnippets, - ImmutableMap multibindingContributionSnippets) { - for (Entry subgraphEntry : input.subgraphs().entrySet()) { - TypeName componentType = - TypeNames.forTypeMirror(subgraphEntry.getKey().getReturnType()); - - ClassWriter subcomponentWriter = componentWriter.addNestedClass( - subgraphEntry.getValue().componentDescriptor().componentDefinitionType().getSimpleName() - + "Impl"); + ImmutableMap parentMultibindingContributionSnippets, + ExecutableElement subcomponentFactoryMethod, + BindingGraph subgraph) { + TypeName subcomponentType = + TypeNames.forTypeMirror(subcomponentFactoryMethod.getReturnType()); - subcomponentWriter.addModifiers(PRIVATE, FINAL); - subcomponentWriter.addImplementedType(componentType); + ClassWriter subcomponentWriter = componentWriter.addNestedClass( + subgraph.componentDescriptor().componentDefinitionType().getSimpleName() + + "Impl"); - writeSubcomponent(subgraphEntry.getValue(), - subcomponentWriter, - proxyWriters, - ImmutableMap.copyOf(componentContributionFields), - multibindingContributionSnippets, - parentMemberSelectSnippets); - - MethodWriter componentMethod = componentWriter.addMethod(componentType, - subgraphEntry.getKey().getSimpleName().toString()); - componentMethod.addModifiers(PUBLIC); - componentMethod.annotate(Override.class); - // TODO(gak): need to pipe through the method params - componentMethod.body().addSnippet("return new %s();", - subcomponentWriter.name()); - } - } + subcomponentWriter.addModifiers(PRIVATE, FINAL); + subcomponentWriter.addImplementedType(subcomponentType); - private ImmutableMap writeSubcomponent( - BindingGraph input, ClassWriter componentWriter, - Set proxyWriters, - ImmutableMap parentContributionFields, - ImmutableMap parentMultibindingContributionSnippets, - ImmutableMap parentMemberSelectSnippets) { - // the full set of types that calling code uses to construct a component instance - ImmutableMap componentContributionNames = - ImmutableMap.copyOf(Maps.asMap( - Sets.union( - input.transitiveModules().keySet(), - input.componentDescriptor().dependencies()), - new Function() { - @Override public String apply(TypeElement input) { - return CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, input.getSimpleName().toString()); - } - })); + MethodWriter componentMethod = componentWriter.addMethod(subcomponentType, + subcomponentFactoryMethod.getSimpleName().toString()); + componentMethod.addModifiers(PUBLIC); + componentMethod.annotate(Override.class); - ConstructorWriter constructorWriter = componentWriter.addConstructor(); + ConstructorWriter constructorWriter = subcomponentWriter.addConstructor(); constructorWriter.addModifiers(PRIVATE); + constructorWriter.body(); Map componentContributionFields = Maps.newHashMap(parentContributionFields); + ImmutableList.Builder subcomponentConstructorParameters = ImmutableList.builder(); + + for (VariableElement moduleVariable : subcomponentFactoryMethod.getParameters()) { + // safe because this passed validation + TypeElement moduleType = MoreTypes.asTypeElement(moduleVariable.asType()); + verify(subgraph.transitiveModules().containsKey(moduleType)); + componentMethod.addParameter( + TypeNames.forTypeMirror(moduleVariable.asType()), + moduleVariable.getSimpleName().toString()); + if (!componentContributionFields.containsKey(moduleType)) { + String preferredModuleName = CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, + moduleType.getSimpleName().toString()); + FieldWriter contributionField = + subcomponentWriter.addField(moduleType, preferredModuleName); + contributionField.addModifiers(PRIVATE, FINAL); + String actualModuleName = contributionField.name(); + constructorWriter.addParameter( + TypeNames.forTypeMirror(moduleVariable.asType()), actualModuleName); + constructorWriter.body().addSnippet(Snippet.format(Joiner.on('\n').join( + "if (%s == null) {", + " throw new NullPointerException();", + "}"), actualModuleName)); + constructorWriter.body().addSnippet( + Snippet.format("this.%1$s = %1$s;", actualModuleName)); + MemberSelect moduleSelect = MemberSelect.instanceSelect( + subcomponentWriter.name(), Snippet.format(actualModuleName)); + componentContributionFields.put(moduleType, moduleSelect); + subcomponentConstructorParameters.add(Snippet.format("%s", moduleVariable.getSimpleName())); + } + } - for (Entry entry : componentContributionNames.entrySet()) { - TypeElement contributionElement = entry.getKey(); - String contributionName = entry.getValue(); + SetView uninitializedModules = Sets.difference( + subgraph.transitiveModules().keySet(), componentContributionFields.keySet()); + for (TypeElement moduleType : uninitializedModules) { + String preferredModuleName = CaseFormat.UPPER_CAMEL.to(LOWER_CAMEL, + moduleType.getSimpleName().toString()); FieldWriter contributionField = - componentWriter.addField(contributionElement, contributionName); - if (hasNoArgsConstructor(entry.getKey())) { - contributionField.setInitializer(Snippet.format("new %s()", - ClassName.fromTypeElement(entry.getKey()))); - } + subcomponentWriter.addField(moduleType, preferredModuleName); contributionField.addModifiers(PRIVATE, FINAL); - componentContributionFields.put(contributionElement, MemberSelect.instanceSelect( - componentWriter.name(), Snippet.format(contributionField.name()))); + String actualModuleName = contributionField.name(); + constructorWriter.body().addSnippet( + Snippet.format("this.%s = new %s();", actualModuleName, + ClassName.fromTypeElement(moduleType))); + MemberSelect moduleSelect = MemberSelect.instanceSelect( + subcomponentWriter.name(), Snippet.format(actualModuleName)); + componentContributionFields.put(moduleType, moduleSelect); } + componentMethod.body().addSnippet("return new %s(%s);", + subcomponentWriter.name(), + Snippet.makeParametersSnippet(subcomponentConstructorParameters.build())); + Map memberSelectSnippetsBuilder = Maps.newHashMap(); Map multibindingContributionSnippetsBuilder = Maps.newHashMap(); @@ -418,8 +429,8 @@ private ImmutableMap writeSubcomponent( Map packageProxies = Maps.newHashMap(); - writeFields(input, - componentWriter, + writeFields(subgraph, + subcomponentWriter, proxyWriters, memberSelectSnippetsBuilder, parentMultibindingContributionSnippets, @@ -440,8 +451,8 @@ private ImmutableMap writeSubcomponent( ImmutableMap.copyOf(multibindingContributionSnippetsBuilder); ImmutableSet enumBindingKeys = enumBindingKeysBuilder.build(); - initializeFrameworkTypes(input, - componentWriter, + initializeFrameworkTypes(subgraph, + subcomponentWriter, constructorWriter, Optional.absent(), componentContributionFields, @@ -449,19 +460,20 @@ private ImmutableMap writeSubcomponent( parentMultibindingContributionSnippets, multibindingContributionSnippets); - writeInterfaceMethods(input, componentWriter, memberSelectSnippets, enumBindingKeys); + writeInterfaceMethods(subgraph, subcomponentWriter, memberSelectSnippets, enumBindingKeys); - writeSubcomponents(input, - componentWriter, - proxyWriters, - componentContributionFields, - memberSelectSnippets, - new ImmutableMap.Builder() - .putAll(parentMultibindingContributionSnippets) - .putAll(multibindingContributionSnippets) - .build()); - - return memberSelectSnippets; + for (Entry subgraphEntry : subgraph.subgraphs().entrySet()) { + writeSubcomponent(subcomponentWriter, + proxyWriters, + componentContributionFields, + memberSelectSnippets, + new ImmutableMap.Builder() + .putAll(parentMultibindingContributionSnippets) + .putAll(multibindingContributionSnippets) + .build(), + subgraphEntry.getKey(), + subgraphEntry.getValue()); + } } private void writeFields(BindingGraph input, @@ -758,9 +770,11 @@ private void initializeFrameworkTypes(BindingGraph input, ImmutableSet provisionBindings = (ImmutableSet) bindings; for (ProvisionBinding provisionBinding : provisionBindings) { - if (!isNonProviderMap(provisionBinding)) { + if (!isNonProviderMap(provisionBinding) + && multibindingContributionSnippets.containsKey(provisionBinding)) { + Snippet snippet = multibindingContributionSnippets.get(provisionBinding); initializeMethod.body().addSnippet("this.%s = %s;", - multibindingContributionSnippets.get(provisionBinding), + snippet, initializeFactoryForProvisionBinding(provisionBinding, componentWriter.name(), input.componentDescriptor().dependencyMethodIndex(), @@ -771,7 +785,11 @@ private void initializeFrameworkTypes(BindingGraph input, if (!provisionBindings.isEmpty()) { Snippet initializeMapSnippet = initializeMapBinding( componentWriter.name(), memberSelectSnippets, - multibindingContributionSnippets, provisionBindings); + new ImmutableMap.Builder() + .putAll(parentMultibindingContributionSnippets) + .putAll(multibindingContributionSnippets) + .build(), + provisionBindings); initializeMethod.body().addSnippet("this.%s = %s;", memberSelectSnippet, initializeMapSnippet); } @@ -1278,18 +1296,4 @@ private boolean isNonProviderMap(Binding binding) { return MoreTypes.isTypeOf(Map.class, bindingType) // Implicitly guarantees a declared type. && !MoreTypes.isTypeOf(Provider.class, asDeclared(bindingType).getTypeArguments().get(1)); } - - private boolean hasNoArgsConstructor(TypeElement type) { - if (type.getNestingKind().equals(TOP_LEVEL) - || type.getNestingKind().equals(MEMBER) && type.getModifiers().contains(STATIC)) { - for (Element enclosed : type.getEnclosedElements()) { - if (enclosed.getKind().equals(CONSTRUCTOR)) { - if (((ExecutableElement) enclosed).getParameters().isEmpty()) { - return true; - } - } - } - } - return false; - } } diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java index a298e8aff44..3c163ce5fce 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java @@ -15,10 +15,6 @@ */ package dagger.internal.codegen; -import java.util.EnumSet; - -import javax.tools.Diagnostic; -import java.util.Arrays; import com.google.auto.common.BasicAnnotationProcessor; import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableList; @@ -27,6 +23,7 @@ import dagger.Provides; import dagger.producers.ProducerModule; import dagger.producers.Produces; +import java.util.EnumSet; import java.util.Map; import java.util.Set; import javax.annotation.processing.Filer; @@ -36,6 +33,8 @@ 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; /** @@ -85,7 +84,8 @@ protected Iterable initSteps() { ModuleValidator moduleValidator = new ModuleValidator(types, elements, methodSignatureFormatter, Module.class, Provides.class); ProvidesMethodValidator providesMethodValidator = new ProvidesMethodValidator(elements); - ComponentValidator componentValidator = new ComponentValidator(moduleValidator); + ComponentValidator componentValidator = + new ComponentValidator(elements, types, moduleValidator); MapKeyValidator mapKeyValidator = new MapKeyValidator(); ModuleValidator producerModuleValidator = new ModuleValidator(types, elements, methodSignatureFormatter, ProducerModule.class, Produces.class); diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java index ed99925e989..022275750fc 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentValidator.java @@ -15,17 +15,42 @@ */ 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.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 com.google.common.collect.Sets; +import com.google.common.collect.Sets.SetView; import dagger.Component; +import dagger.Module; +import dagger.Subcomponent; +import java.util.List; +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.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.getComponentModules; +import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules; +import static dagger.internal.codegen.Util.componentCanMakeNewInstances; 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. @@ -33,12 +58,16 @@ * @author Gregory Kick */ final class ComponentValidator implements Validator { + private final Elements elements; + private final Types types; private final ModuleValidator moduleValidator; - - ComponentValidator(ModuleValidator moduleValidator) { + + ComponentValidator(Elements elements, Types types, ModuleValidator moduleValidator) { + this.elements = elements; + this.types = types; this.moduleValidator = moduleValidator; } - + @Override public ValidationReport validate(final TypeElement subject) { final ValidationReport.Builder builder = ValidationReport.Builder.about(subject); @@ -47,9 +76,131 @@ final class ComponentValidator implements Validator { builder.addItem("@Component may only be applied to an interface or abstract class", subject); } + List members = elements.getAllMembers(subject); + for (ExecutableElement method : ElementFilter.methodsIn(members)) { + if (method.getModifiers().contains(ABSTRACT)) { + List parameters = method.getParameters(); + TypeMirror returnType = method.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 subcomponentAnnotation = returnType.accept( + new SimpleTypeVisitor6, Void>() { + @Override protected Optional defaultAction(TypeMirror e, Void p) { + return Optional.absent(); + } + + @Override public Optional visitDeclared(DeclaredType t, Void p) { + return MoreElements.getAnnotationMirror(t.asElement(), Subcomponent.class); + } + }, null); + if (subcomponentAnnotation.isPresent()) { + validateSubcomponentMethod( + builder, method, parameters, returnType, subcomponentAnnotation); + } 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 + VariableElement onlyParameter = Iterables.getOnlyElement(parameters); + if (!(returnType.getKind().equals(VOID) + || types.isSameType(returnType, onlyParameter.asType()))) { + builder.addItem( + "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.addItem( + "This method isn't a valid provision method, members injection method or " + + "subcomponent factory method. Dagger cannot implement this method", method); + break; + } + } + } + } + AnnotationMirror componentMirror = getAnnotationMirror(subject, Component.class).get(); ImmutableList moduleTypes = getComponentModules(componentMirror); moduleValidator.validateReferencedModules(subject, builder, moduleTypes); return builder.build(); } + + private void validateSubcomponentMethod(final ValidationReport.Builder builder, + ExecutableElement method, List parameters, TypeMirror returnType, + Optional subcomponentAnnotation) { + ImmutableSet moduleTypes = + MoreTypes.asTypeElements(getComponentModules(subcomponentAnnotation.get())); + + ImmutableSet transitiveModules = + getTransitiveModules(types, elements, moduleTypes); + + ImmutableSet requiredModules = + FluentIterable.from(transitiveModules) + .filter(new Predicate() { + @Override public boolean apply(TypeElement input) { + return !componentCanMakeNewInstances(input); + } + }) + .toSet(); + + Set variableTypes = Sets.newHashSet(); + + for (VariableElement parameter : parameters) { + Optional moduleType = parameter.asType().accept( + new SimpleTypeVisitor6, Void>() { + @Override protected Optional defaultAction(TypeMirror e, Void p) { + return Optional.absent(); + } + + @Override public Optional visitDeclared(DeclaredType t, Void p) { + return MoreElements.isAnnotationPresent(t.asElement(), Module.class) + ? Optional.of(MoreTypes.asTypeElement(t)) + : Optional.absent(); + } + }, null); + if (moduleType.isPresent()) { + if (variableTypes.contains(moduleType.get())) { + builder.addItem( + 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.addItem( + 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.addItem( + String.format( + "Subcomponent factory methods may only accept modules, but %s is not.", + parameter.asType()), + parameter); + } + } + + SetView missingModules = + Sets.difference(requiredModules, ImmutableSet.copyOf(variableTypes)); + if (!missingModules.isEmpty()) { + builder.addItem( + String.format( + "%s requires modules which have no visible default constructors. " + + "Add the following modules as parameters to this method: %s", + MoreTypes.asTypeElement(returnType).getQualifiedName(), + Joiner.on(", ").join(missingModules)), + method); + } + } } diff --git a/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java index 3a91a1e3417..de60f4285a0 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java +++ b/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java @@ -15,8 +15,6 @@ */ package dagger.internal.codegen; -import javax.lang.model.type.DeclaredType; - import com.google.auto.common.AnnotationMirrors; import com.google.auto.common.MoreElements; import com.google.auto.common.MoreTypes; @@ -24,10 +22,9 @@ 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.Maps; import com.google.common.collect.Queues; +import com.google.common.collect.Sets; import dagger.Component; import dagger.MapKey; import dagger.Module; @@ -35,8 +32,8 @@ import dagger.producers.ProducerModule; import dagger.producers.ProductionComponent; import java.util.List; -import java.util.Map; 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.Element; @@ -47,6 +44,7 @@ import javax.lang.model.util.Elements; 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; @@ -95,7 +93,7 @@ static ImmutableList getModuleInjects(AnnotationMirror moduleAnnotat static ImmutableSet getMapKeys(Element element) { return AnnotationMirrors.getAnnotatedAnnotations(element, MapKey.class); } - + /** Returns the first type that specifies this' nullability, or absent if none. */ static Optional getNullableType(Element element) { List mirrors = element.getAnnotationMirrors(); @@ -124,11 +122,11 @@ static ImmutableList convertClassArrayToListOfTypes( * 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. */ - static ImmutableMap> getTransitiveModules( - Types types, Elements elements, ImmutableSet seedModules) { + static ImmutableSet getTransitiveModules( + Types types, Elements elements, Iterable seedModules) { TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType(); Queue moduleQueue = Queues.newArrayDeque(seedModules); - Map> moduleElements = Maps.newLinkedHashMap(); + Set moduleElements = Sets.newLinkedHashSet(); for (TypeElement moduleElement = moduleQueue.poll(); moduleElement != null; moduleElement = moduleQueue.poll()) { @@ -143,15 +141,15 @@ static ImmutableMap> getTransitiveModules // against this element, not the parent.) addIncludesFromSuperclasses(types, moduleElement, moduleDependenciesBuilder, objectType); ImmutableSet moduleDependencies = moduleDependenciesBuilder.build(); - moduleElements.put(moduleElement, moduleDependencies); + moduleElements.add(moduleElement); for (TypeElement dependencyType : moduleDependencies) { - if (!moduleElements.containsKey(dependencyType)) { + if (!moduleElements.contains(dependencyType)) { moduleQueue.add(dependencyType); } } } } - return ImmutableMap.copyOf(moduleElements); + return ImmutableSet.copyOf(moduleElements); } static boolean isSubcomponentType(TypeMirror type) { diff --git a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java index 8604eee34f5..53b5d223283 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java +++ b/compiler/src/main/java/dagger/internal/codegen/ErrorMessages.java @@ -161,7 +161,7 @@ final class ErrorMessages { static final String PROVIDES_OR_PRODUCES_METHOD_MULTIPLE_QUALIFIERS = "Cannot use more than one @Qualifier on a @Provides or @Produces method"; - /*mapKey errors*/ + /* mapKey errors*/ static final String MAPKEY_WITHOUT_FIELDS = "Map key annotation does not have fields"; diff --git a/compiler/src/main/java/dagger/internal/codegen/Util.java b/compiler/src/main/java/dagger/internal/codegen/Util.java index 2b633b33bc2..58ad95c3639 100644 --- a/compiler/src/main/java/dagger/internal/codegen/Util.java +++ b/compiler/src/main/java/dagger/internal/codegen/Util.java @@ -27,6 +27,7 @@ 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.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -36,6 +37,9 @@ import javax.lang.model.util.SimpleAnnotationValueVisitor6; 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.STATIC; /** * Utilities for handling types in annotation processors @@ -120,5 +124,56 @@ static Optional unwrapOptionalEquivalence( : Optional.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()) { + return true; + } + } + + // TODO(gak): still need checks for visibility + + return false; + } + private Util() {} } 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 00000000000..cf15210eef7 --- /dev/null +++ b/compiler/src/test/java/dagger/internal/codegen/SubcomponentValidationTest.java @@ -0,0 +1,195 @@ +/* + * 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 {}"); + JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ModuleWithParameters", + "package test;", + "", + "import dagger.Module;", + "", + "@Module", + "final class ModuleWithParameters {", + " ModuleWithParameters(Object whatever) {}", + "}"); + 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"); + } +} From 86eed8042351b5998e1804a630dffd25031c9fc9 Mon Sep 17 00:00:00 2001 From: gak Date: Mon, 30 Mar 2015 16:46:07 -0700 Subject: [PATCH 03/16] Ensure that components can also be abstract classes. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=89915663 --- .../test/BasicAbstractClassComponent.java | 29 +++++++++++++++ .../src/test/java/test/BasicTest.java | 37 +++++++++---------- .../internal/codegen/ComponentGenerator.java | 17 ++++++++- 3 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 compiler/src/it/functional-tests/src/main/java/test/BasicAbstractClassComponent.java 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 00000000000..78f77dfb804 --- /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/test/java/test/BasicTest.java b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java index c3bfa98fa73..76a69eeedfd 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java @@ -15,9 +15,10 @@ */ package test; -import org.junit.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 org.junit.runners.JUnit4; import static com.google.common.truth.Truth.assertThat; import static test.PrimitivesModule.BOUND_BOOLEAN; @@ -37,10 +38,15 @@ import static test.PrimitivesModule.BOUND_SHORT; import static test.PrimitivesModule.BOUND_SHORT_ARRAY; -@RunWith(JUnit4.class) +@RunWith(Theories.class) public class BasicTest { - @Test public void primitives() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @DataPoint + public static final BasicComponent basicComponent = Dagger_BasicComponent.create(); + @DataPoint + public static final BasicComponent abstractClassBasicComponent = + Dagger_BasicAbstractClassComponent.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); @@ -51,8 +57,7 @@ public class BasicTest { assertThat(basicComponent.getDouble()).isEqualTo(BOUND_DOUBLE); } - @Test public void boxedPrimitives() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @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)); @@ -63,8 +68,7 @@ public class BasicTest { assertThat(basicComponent.getBoxedDouble()).isEqualTo(new Double(BOUND_DOUBLE)); } - @Test public void boxedPrimitiveProviders() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @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)); @@ -75,8 +79,7 @@ public class BasicTest { assertThat(basicComponent.getDoubleProvider().get()).isEqualTo(new Double(BOUND_DOUBLE)); } - @Test public void primitiveArrays() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @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); @@ -87,8 +90,7 @@ public class BasicTest { assertThat(basicComponent.getDoubleArray()).isSameAs(BOUND_DOUBLE_ARRAY); } - @Test public void primitiveArrayProviders() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @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); @@ -99,19 +101,16 @@ public class BasicTest { assertThat(basicComponent.getDoubleArrayProvider().get()).isSameAs(BOUND_DOUBLE_ARRAY); } - @Test public void noOpMembersInjection() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @Theory public void noOpMembersInjection(BasicComponent basicComponent) { Object object = new Object(); assertThat(basicComponent.noOpMembersInjection(object)).isSameAs(object); } - @Test public void basicObject_noDeps() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @Theory public void basicObject_noDeps(BasicComponent basicComponent) { assertThat(basicComponent.thing()).isNotNull(); } - @Test public void inheritedMembersInjection() { - BasicComponent basicComponent = Dagger_BasicComponent.create(); + @Theory public void inheritedMembersInjection(BasicComponent basicComponent) { assertThat(basicComponent.typeWithInheritedMembersInjection().thing).isNotNull(); } } diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index 72540b0bf9a..f35ebba6e37 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -90,6 +90,7 @@ import static com.google.auto.common.MoreTypes.asDeclared; import static com.google.common.base.CaseFormat.LOWER_CAMEL; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Verify.verify; import static dagger.internal.codegen.Binding.bindingPackageFor; import static dagger.internal.codegen.ConfigurationAnnotations.getMapKeys; @@ -102,6 +103,7 @@ import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement; import static dagger.internal.codegen.SourceFiles.membersInjectorNameForMembersInjectionBinding; import static dagger.internal.codegen.Util.componentCanMakeNewInstances; +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; @@ -199,15 +201,26 @@ Snippet getSnippetFor(ClassName usingClass) { @Override ImmutableSet write(ClassName componentName, BindingGraph input) { + TypeElement componentDefinitionType = input.componentDescriptor().componentDefinitionType(); ClassName componentDefinitionTypeName = - ClassName.fromTypeElement(input.componentDescriptor().componentDefinitionType()); + ClassName.fromTypeElement(componentDefinitionType); JavaWriter writer = JavaWriter.inPackage(componentName.packageName()); ClassWriter componentWriter = writer.addClass(componentName.simpleName()); componentWriter.annotate(Generated.class).setValue(ComponentProcessor.class.getCanonicalName()); componentWriter.addModifiers(PUBLIC, FINAL); - componentWriter.addImplementedType(componentDefinitionTypeName); + switch (componentDefinitionType.getKind()) { + case CLASS: + checkState(componentDefinitionType.getModifiers().contains(ABSTRACT)); + componentWriter.setSuperType(componentDefinitionTypeName); + break; + case INTERFACE: + componentWriter.addImplementedType(componentDefinitionTypeName); + break; + default: + throw new IllegalStateException(); + } Set javaWriters = Sets.newHashSet(); javaWriters.add(writer); From 409ecbeaa2abb911449c4a9c6f567af3fe26b1e2 Mon Sep 17 00:00:00 2001 From: gak Date: Tue, 31 Mar 2015 11:04:03 -0700 Subject: [PATCH 04/16] Rework the binding graph validator to properly detect cycles. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=89982588 --- .../codegen/BindingGraphValidator.java | 84 +++++++------------ 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java index 8e3022e2bb7..a1e0b69621e 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java @@ -41,7 +41,6 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.Formatter; -import java.util.HashSet; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; @@ -119,28 +118,7 @@ private ValidationReport validate(final BindingGraph subject, validateDependencyScopes(subject, reportBuilder); for (DependencyRequest entryPoint : subject.entryPoints()) { - Deque path = new ArrayDeque<>(); - path.push(ResolvedRequest.create(entryPoint, subject)); - traversalHelper(subject, path, new Traverser() { - final Set visitedBindings = new HashSet<>(); - - @Override - boolean visitResolvedRequest(Deque path) { - ResolvedBindings binding = path.peek().binding(); - for (ResolvedRequest resolvedRequest : Iterables.skip(path, 1)) { - if (resolvedRequest.request().bindingKey().equals(binding.bindingKey())) { - reportCycle(path, reportBuilder); - return false; - } - } - - if (!visitedBindings.add(binding.bindingKey())) { - return false; - } - - return validateResolvedBinding(path, binding, reportBuilder); - } - }); + traverseRequest(entryPoint, new ArrayDeque(), subject, reportBuilder); } validateSubcomponents(subject, reportBuilder); @@ -148,6 +126,31 @@ boolean visitResolvedRequest(Deque path) { return reportBuilder.build(); } + private void traverseRequest( + DependencyRequest request, + Deque bindingPath, + BindingGraph graph, + ValidationReport.Builder reportBuilder) { + BindingKey requestKey = request.bindingKey(); + for (ResolvedRequest pathElement : bindingPath) { + if (pathElement.request().bindingKey().equals(requestKey)) { + reportCycle(request, bindingPath, reportBuilder); + return; + } + } + + ResolvedRequest resolvedRequest = ResolvedRequest.create(request, graph); + bindingPath.push(resolvedRequest); + validateResolvedBinding(bindingPath, resolvedRequest.binding(), reportBuilder); + + for (Binding binding : resolvedRequest.binding().bindings()) { + for (DependencyRequest nextRequest : binding.implicitDependencies()) { + traverseRequest(nextRequest, bindingPath, graph, reportBuilder); + } + } + bindingPath.poll(); + } + private void validateSubcomponents(BindingGraph graph, ValidationReport.Builder reportBuilder) { for (Entry subgraphEntry : graph.subgraphs().entrySet()) { @@ -197,7 +200,7 @@ private boolean validateResolvedBinding( "contribution binding keys should never have members injection bindings"); } Set combined = Sets.union(provisionBindings, productionBindings); - if (!validateNullability(path, combined, reportBuilder)) { + if (!validateNullability(path.peek().request(), combined, reportBuilder)) { return false; } if (!productionBindings.isEmpty() && doesPathRequireProvisionOnly(path)) { @@ -241,10 +244,9 @@ private boolean validateResolvedBinding( } /** Ensures that if the request isn't nullable, then each contribution is also not nullable. */ - private boolean validateNullability(Deque requestPath, + private boolean validateNullability(DependencyRequest request, Set bindings, Builder reportBuilder) { boolean valid = true; - DependencyRequest request = requestPath.peek().request(); String typeName = TypeNames.forTypeMirror(request.key().type()).toString(); if (!request.isNullable()) { for (ContributionBinding binding : bindings) { @@ -735,10 +737,10 @@ private String formatBindingType(BindingType type) { } } - private void reportCycle(Deque path, + private void reportCycle(DependencyRequest request, Deque path, final ValidationReport.Builder reportBuilder) { - ImmutableList printableDependencyPath = FluentIterable.from(path) - .transform(REQUEST_FROM_RESOLVED_REQUEST) + ImmutableList printableDependencyPath = FluentIterable.of(request) + .append(Iterables.transform(path, REQUEST_FROM_RESOLVED_REQUEST)) .transform(dependencyRequestFormatter) .filter(Predicates.not(Predicates.equalTo(""))) .toList() @@ -752,7 +754,7 @@ private void reportCycle(Deque path, componentType.getQualifiedName(), rootRequest.requestElement().getSimpleName(), Joiner.on("\n") - .join(printableDependencyPath.subList(1, printableDependencyPath.size()))), + .join(printableDependencyPath.subList(1, printableDependencyPath.size()))), rootRequest.requestElement()); } @@ -779,28 +781,6 @@ static ResolvedRequest create(DependencyRequest request, BindingGraph graph) { } }; - private void traversalHelper(BindingGraph graph, Deque path, - Traverser traverser) { - ImmutableSet allDeps = - FluentIterable.from(path.peek().binding().bindings()) - .transformAndConcat( - new Function>() { - @Override - public Set apply(Binding input) { - return input.implicitDependencies(); - } - }) - .toSet(); - boolean descend = traverser.visitResolvedRequest(path); - if (descend) { - for (DependencyRequest dependency : allDeps) { - path.push(ResolvedRequest.create(dependency, graph)); - traversalHelper(graph, path, traverser); - path.pop(); - } - } - } - abstract static class Traverser { abstract boolean visitResolvedRequest(Deque path); } From 4c3b97c015df219fce6ab51ef1553c5cb0deb4fb Mon Sep 17 00:00:00 2001 From: sameb Date: Tue, 31 Mar 2015 13:42:40 -0700 Subject: [PATCH 05/16] Add a default value to MapKey#unwrapValue (Once Guice syncs with google's internal both systems will share this behavior) ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=89998087 --- core/src/main/java/dagger/MapKey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/dagger/MapKey.java b/core/src/main/java/dagger/MapKey.java index ca88661c9e7..c6bf6d70a79 100644 --- a/core/src/main/java/dagger/MapKey.java +++ b/core/src/main/java/dagger/MapKey.java @@ -54,5 +54,5 @@ * annotation will be the key type for injected map and the value instances will be the keys. * Currently only support {@code unwrapValue} to be true. */ - boolean unwrapValue(); + boolean unwrapValue() default true; } From c57e1fd97d89d4a80db37a8194c5678149d90c34 Mon Sep 17 00:00:00 2001 From: gak Date: Tue, 31 Mar 2015 15:34:28 -0700 Subject: [PATCH 06/16] Add more permutations to the test for injection types. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90009415 --- .../src/main/java/test/BasicComponent.java | 2 + .../src/main/java/test/InjectedThing.java | 225 ++++++++++++++++++ .../test/NonComponentDependencyComponent.java | 2 +- .../internal/codegen/ComponentGenerator.java | 15 +- .../internal/codegen/ComponentProcessor.java | 3 +- .../java/dagger/internal/codegen/Key.java | 29 +-- .../dagger/internal/codegen/SourceFiles.java | 13 +- 7 files changed, 261 insertions(+), 28 deletions(-) create mode 100644 compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java 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 index 2a0eab6ba6c..0f8fe75bb85 100644 --- a/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java +++ b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java @@ -68,5 +68,7 @@ interface BasicComponent { Object noOpMembersInjection(Object obviouslyDoesNotHaveMembersToInject); Thing thing(); + InjectedThing injectedThing(); + TypeWithInheritedMembersInjection typeWithInheritedMembersInjection(); } 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 00000000000..a28a6ff2d55 --- /dev/null +++ b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java @@ -0,0 +1,225 @@ +/* + * 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; + +@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 byteProvider; + @Inject Provider charProvider; + @Inject Provider shortProvider; + @Inject Provider intProvider; + @Inject Provider longProvider; + @Inject Provider booleanProvider; + @Inject Provider floatProvider; + @Inject Provider doubleProvider; + + @Inject Lazy lazyByte; + @Inject Lazy lazyChar; + @Inject Lazy lazyShort; + @Inject Lazy lazyInt; + @Inject Lazy lazyLong; + @Inject Lazy lazyBoolean; + @Inject Lazy lazyFloat; + @Inject Lazy 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 byteArrayProvider; + @Inject Provider charArrayProvider; + @Inject Provider shortArrayProvider; + @Inject Provider intArrayProvider; + @Inject Provider longArrayProvider; + @Inject Provider booleanArrayProvider; + @Inject Provider floatArrayProvider; + @Inject Provider doubleArrayProvider; + + @Inject Lazy lazyByteArray; + @Inject Lazy lazyCharArray; + @Inject Lazy lazyShortArray; + @Inject Lazy lazyIntArray; + @Inject Lazy lazyLongArray; + @Inject Lazy lazyBooleanArray; + @Inject Lazy lazy; + @Inject Lazy lazyDoubleArray; + + @Inject Thing thing; + @Inject Provider thingProvider; + @Inject Lazy lazyThing; + + @Inject InjectedThing( + byte primitiveByte, + char primitiveChar, + short primitiveShort, + int primitiveInt, + long primitiveLong, + boolean primitiveBoolean, + float primitiveFloat, + double primitiveDouble, + + Provider byteProvider, + Provider charProvider, + Provider shortProvider, + Provider intProvider, + Provider longProvider, + Provider booleanProvider, + Provider floatProvider, + Provider doubleProvider, + + Lazy lazyByte, + Lazy lazyChar, + Lazy lazyShort, + Lazy lazyInt, + Lazy lazyLong, + Lazy lazyBoolean, + Lazy lazyFloat, + Lazy 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 byteArrayProvider, + Provider charArrayProvider, + Provider shortArrayProvider, + Provider intArrayProvider, + Provider longArrayProvider, + Provider booleanArrayProvider, + Provider floatArrayProvider, + Provider doubleArrayProvider, + + Lazy lazyByteArray, + Lazy lazyCharArray, + Lazy lazyShortArray, + Lazy lazyIntArray, + Lazy lazyLongArray, + Lazy lazyBooleanArray, + Lazy lazy, + Lazy lazyDoubleArray, + + Thing thing, + Provider thingProvider, + Lazy lazyThing) {} + + @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 byteProvider) {} + @Inject void charProvider(Provider charProvider) {} + @Inject void shortProvider(Provider shortProvider) {} + @Inject void intProvider(Provider intProvider) {} + @Inject void longProvider(Provider longProvider) {} + @Inject void booleanProvider(Provider booleanProvider) {} + @Inject void floatProvider(Provider floatProvider) {} + @Inject void doubleProvider(Provider doubleProvider) {} + + @Inject void lazyByte(Lazy lazyByte) {} + @Inject void lazyChar(Lazy lazyChar) {} + @Inject void lazyShort(Lazy lazyShort) {} + @Inject void lazyInt(Lazy lazyInt) {} + @Inject void lazyLong(Lazy lazyLong) {} + @Inject void lazyBoolean(Lazy lazyBoolean) {} + @Inject void lazyFloat(Lazy lazyFloat) {} + @Inject void lazyDouble(Lazy 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 byteArrayProvider) {} + @Inject void charArrayProvider(Provider charArrayProvider) {} + @Inject void shortArrayProvider(Provider shortArrayProvider) {} + @Inject void intArrayProvider(Provider intArrayProvider) {} + @Inject void longArrayProvider(Provider longArrayProvider) {} + @Inject void booleanArrayProvider(Provider booleanArrayProvider) {} + @Inject void floatArrayProvider(Provider floatArrayProvider) {} + @Inject void doubleArrayProvider(Provider doubleArrayProvider) {} + + @Inject void lazyByteArray(Lazy lazyByteArray) {} + @Inject void lazyCharArray(Lazy lazyCharArray) {} + @Inject void lazyShortArray(Lazy lazyShortArray) {} + @Inject void lazyIntArray(Lazy lazyIntArray) {} + @Inject void lazyLongArray(Lazy lazyLongArray) {} + @Inject void lazyBooleanArray(Lazy lazyBooleanArray) {} + @Inject void lazy(Lazy lazy) {} + @Inject void lazyDoubleArray(Lazy lazyDoubleArray) {} + + @Inject void thing(Thing thing) {} + @Inject void thingProvider(Provider thingProvider) {} + @Inject void lazyThing(Lazy lazyThing) {} +} 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 index 5521dd7dda7..3f1b8006970 100644 --- a/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java +++ b/compiler/src/it/functional-tests/src/main/java/test/NonComponentDependencyComponent.java @@ -24,7 +24,7 @@ interface NonComponentDependencyComponent { static class ThingTwo { @Inject - ThingTwo(Thing thing) {} + ThingTwo(@SuppressWarnings("unused") Thing thing) {} } // A non-component interface which this interface depends upon. diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index f35ebba6e37..412a36fe1b6 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -86,6 +86,7 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementKindVisitor6; import javax.lang.model.util.SimpleAnnotationValueVisitor6; +import javax.lang.model.util.Types; import javax.tools.Diagnostic; import static com.google.auto.common.MoreTypes.asDeclared; @@ -117,10 +118,12 @@ * @since 2.0 */ final class ComponentGenerator extends SourceFileGenerator { + private final Types types; private final Diagnostic.Kind nullableValidationType; - ComponentGenerator(Filer filer, Diagnostic.Kind nullableValidationType) { + ComponentGenerator(Filer filer, Types types, Diagnostic.Kind nullableValidationType) { super(filer); + this.types = types; this.nullableValidationType = nullableValidationType; } @@ -1096,7 +1099,7 @@ private Snippet initializeFactoryForProductionBinding(ProductionBinding binding, } } - private static Snippet initializeMembersInjectorForBinding( + private Snippet initializeMembersInjectorForBinding( ClassName componentName, MembersInjectionBinding binding, ImmutableMap memberSelectSnippets) { @@ -1123,13 +1126,13 @@ private static Snippet initializeMembersInjectorForBinding( } } - private static List getDependencyParameters( + private List getDependencyParameters( ClassName componentName, Iterable dependencies, ImmutableMap memberSelectSnippets) { ImmutableList.Builder parameters = ImmutableList.builder(); for (Collection requestsForKey : - SourceFiles.indexDependenciesByUnresolvedKey(dependencies).asMap().values()) { + SourceFiles.indexDependenciesByUnresolvedKey(types, dependencies).asMap().values()) { BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey) .transform(new Function() { @Override public BindingKey apply(DependencyRequest request) { @@ -1142,14 +1145,14 @@ private static List getDependencyParameters( return parameters.build(); } - private static List getProducerDependencyParameters( + private List getProducerDependencyParameters( BindingGraph bindingGraph, ClassName componentName, Iterable dependencies, ImmutableMap memberSelectSnippets) { ImmutableList.Builder parameters = ImmutableList.builder(); for (Collection requestsForKey : - SourceFiles.indexDependenciesByUnresolvedKey(dependencies).asMap().values()) { + SourceFiles.indexDependenciesByUnresolvedKey(types, dependencies).asMap().values()) { BindingKey key = Iterables.getOnlyElement(FluentIterable.from(requestsForKey) .transform(new Function() { @Override public BindingKey apply(DependencyRequest request) { diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java index 3c163ce5fce..86c4ffa89b5 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java @@ -98,7 +98,8 @@ protected Iterable initSteps() { new FactoryGenerator(filer, DependencyRequestMapper.FOR_PROVIDER, nullableDiagnosticType); MembersInjectorGenerator membersInjectorGenerator = new MembersInjectorGenerator(filer, elements, types, DependencyRequestMapper.FOR_PROVIDER); - ComponentGenerator componentGenerator = new ComponentGenerator(filer, nullableDiagnosticType); + ComponentGenerator componentGenerator = + new ComponentGenerator(filer, types, nullableDiagnosticType); ProducerFactoryGenerator producerFactoryGenerator = new ProducerFactoryGenerator(filer, DependencyRequestMapper.FOR_PRODUCER); diff --git a/compiler/src/main/java/dagger/internal/codegen/Key.java b/compiler/src/main/java/dagger/internal/codegen/Key.java index 9f48deaa156..ca01668b79c 100644 --- a/compiler/src/main/java/dagger/internal/codegen/Key.java +++ b/compiler/src/main/java/dagger/internal/codegen/Key.java @@ -89,8 +89,14 @@ TypeMirror type() { return wrappedType().get(); } - Key withType(TypeMirror newType) { - return new AutoValue_Key(wrappedQualifier(), MoreTypes.equivalence().wrap(newType)); + 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() { @@ -157,11 +163,6 @@ static final class Factory { this.elements = checkNotNull(elements); } - private TypeMirror normalize(TypeMirror type) { - TypeKind kind = type.getKind(); - return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type; - } - private TypeElement getSetElement() { return elements.getTypeElement(Set.class.getCanonicalName()); } @@ -185,7 +186,7 @@ private TypeElement getClassElement(Class cls) { Key forComponentMethod(ExecutableElement componentMethod) { checkNotNull(componentMethod); checkArgument(componentMethod.getKind().equals(METHOD)); - TypeMirror returnType = normalize(componentMethod.getReturnType()); + TypeMirror returnType = normalize(types, componentMethod.getReturnType()); return new AutoValue_Key( wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(componentMethod)), MoreTypes.equivalence().wrap(returnType)); @@ -194,7 +195,7 @@ Key forComponentMethod(ExecutableElement componentMethod) { Key forProductionComponentMethod(ExecutableElement componentMethod) { checkNotNull(componentMethod); checkArgument(componentMethod.getKind().equals(METHOD)); - TypeMirror returnType = normalize(componentMethod.getReturnType()); + TypeMirror returnType = normalize(types, componentMethod.getReturnType()); TypeMirror keyType = returnType; if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) { keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); @@ -209,7 +210,7 @@ Key forProvidesMethod(ExecutableType executableType, ExecutableElement e) { checkArgument(e.getKind().equals(METHOD)); Provides providesAnnotation = e.getAnnotation(Provides.class); checkArgument(providesAnnotation != null); - TypeMirror returnType = normalize(executableType.getReturnType()); + TypeMirror returnType = normalize(types, executableType.getReturnType()); switch (providesAnnotation.type()) { case UNIQUE: return new AutoValue_Key( @@ -252,7 +253,7 @@ Key forProducesMethod(ExecutableType executableType, ExecutableElement e) { checkArgument(e.getKind().equals(METHOD)); Produces producesAnnotation = e.getAnnotation(Produces.class); checkArgument(producesAnnotation != null); - TypeMirror returnType = normalize(executableType.getReturnType()); + TypeMirror returnType = normalize(types, executableType.getReturnType()); TypeMirror keyType = returnType; if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) { keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); @@ -301,19 +302,19 @@ Key forInjectConstructorWithResolvedType(TypeMirror type) { Key forComponent(TypeMirror type) { return new AutoValue_Key( Optional.>absent(), - MoreTypes.equivalence().wrap(normalize(type))); + MoreTypes.equivalence().wrap(normalize(types, type))); } Key forMembersInjectedType(TypeMirror type) { return new AutoValue_Key( Optional.>absent(), - MoreTypes.equivalence().wrap(normalize(type))); + MoreTypes.equivalence().wrap(normalize(types, type))); } Key forQualifiedType(Optional qualifier, TypeMirror type) { return new AutoValue_Key( wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier), - MoreTypes.equivalence().wrap(normalize(type))); + MoreTypes.equivalence().wrap(normalize(types, type))); } /** diff --git a/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java index bf208a63c78..b183622304c 100644 --- a/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java +++ b/compiler/src/main/java/dagger/internal/codegen/SourceFiles.java @@ -37,6 +37,7 @@ 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; @@ -79,10 +80,10 @@ public int compare(DependencyRequest left, DependencyRequest right) { // 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 indexDependenciesByUnresolvedKey( - Iterable dependencies) { + Types types, Iterable dependencies) { ImmutableSetMultimap.Builder dependenciesByKeyBuilder = - new ImmutableSetMultimap.Builder().orderValuesBy( - DEPENDENCY_ORDERING); + new ImmutableSetMultimap.Builder() + .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 @@ -90,7 +91,7 @@ static ImmutableSetMultimap indexDependenciesByUn TypeMirror unresolvedType = DependencyRequest.Factory.extractKindAndType(dependency.requestElement().asType()).type(); BindingKey unresolved = - BindingKey.create(resolved.kind(), resolved.key().withType(unresolvedType)); + BindingKey.create(resolved.kind(), resolved.key().withType(types, unresolvedType)); dependenciesByKeyBuilder.put(unresolved, dependency); } return dependenciesByKeyBuilder.build(); @@ -106,8 +107,8 @@ static ImmutableSetMultimap indexDependenciesByUn static ImmutableSetMultimap indexDependenciesByKey( Iterable dependencies) { ImmutableSetMultimap.Builder dependenciesByKeyBuilder = - new ImmutableSetMultimap.Builder().orderValuesBy( - DEPENDENCY_ORDERING); + new ImmutableSetMultimap.Builder() + .orderValuesBy(DEPENDENCY_ORDERING); for (DependencyRequest dependency : dependencies) { dependenciesByKeyBuilder.put(dependency.bindingKey(), dependency); } From b67bf105b9cb9fbb4aa9b65c0adc34bafaa42020 Mon Sep 17 00:00:00 2001 From: gak Date: Thu, 2 Apr 2015 18:32:26 -0700 Subject: [PATCH 07/16] Change Dagger components to generate components prefixed with Dagger rather than Dagger_ ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90217115 --- .../src/test/java/test/BasicTest.java | 4 +- .../src/test/java/test/GenericTest.java | 22 +-- .../src/test/java/test/MultibindingTest.java | 2 +- .../java/test/NonComponentDependencyTest.java | 2 +- .../test/membersinject/MembersInjectTest.java | 6 +- .../java/test/nullables/NullabilityTest.java | 4 +- .../test/subcomponent/SubcomponentTest.java | 10 +- .../hiding/SubcomponentHidingTest.java | 2 +- .../src/test/java/test/DependentTest.java | 6 +- .../src/test/java/test/MultibindingTest.java | 2 +- .../src/test/java/test/SimpleTest.java | 2 +- .../internal/codegen/ComponentGenerator.java | 2 +- .../codegen/ComponentProcessorTest.java | 128 +++++++++--------- .../MapBindingComponentProcessorTest.java | 32 ++--- .../internal/codegen/MapKeyProcessorTest.java | 16 +-- .../codegen/MembersInjectionTest.java | 16 +-- .../internal/codegen/PackageProxyTest.java | 28 ++-- .../ProductionComponentProcessorTest.java | 8 +- .../operation/PrimitiveInjectionTest.java | 8 +- core/src/main/java/dagger/Component.java | 4 +- .../activitygraphs/DemoApplication.java | 2 +- .../activitygraphs/ui/HomeActivity.java | 2 +- .../dagger/simple/DemoApplication.java | 2 +- .../src/main/java/coffee/CoffeeApp.java | 2 +- .../main/java/dagger/producers/Producer.java | 2 +- .../dagger/producers/ProductionComponent.java | 4 +- 26 files changed, 159 insertions(+), 159 deletions(-) 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 index 76a69eeedfd..fe9c6afe9b6 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/BasicTest.java @@ -41,10 +41,10 @@ @RunWith(Theories.class) public class BasicTest { @DataPoint - public static final BasicComponent basicComponent = Dagger_BasicComponent.create(); + public static final BasicComponent basicComponent = DaggerBasicComponent.create(); @DataPoint public static final BasicComponent abstractClassBasicComponent = - Dagger_BasicAbstractClassComponent.create(); + DaggerBasicAbstractClassComponent.create(); @Theory public void primitives(BasicComponent basicComponent) { assertThat(basicComponent.getByte()).isEqualTo(BOUND_BYTE); 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 index 88be63f0e5c..f1c981f254f 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/GenericTest.java @@ -32,17 +32,17 @@ public class GenericTest { @Test public void testGenericComponentCreate() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); assertThat(component).isNotNull(); } @Test public void testGenericSimpleReferences() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); assertThat(component.referencesGeneric().genericA.t).isNotNull(); } @Test public void testGenericDoubleReferences() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); GenericDoubleReferences doubleA = component.doubleGenericA(); assertThat(doubleA.a).isNotNull(); assertThat(doubleA.a2).isNotNull(); @@ -57,13 +57,13 @@ public class GenericTest { } @Test public void complexGenerics() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); // validate these can be called w/o exceptions. component.complexGenerics(); } @Test public void noDepsGenerics() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); // validate these can be called w/o exceptions. component.noDepsA(); component.noDepsB(); @@ -71,7 +71,7 @@ public class GenericTest { @Test public void boundedGenerics() { BoundedGenericModule expected = new BoundedGenericModule(); - BoundedGenericComponent component = Dagger_BoundedGenericComponent.create(); + BoundedGenericComponent component = DaggerBoundedGenericComponent.create(); BoundedGenerics, LinkedList, Integer, List> b1 = component.bounds1(); assertEquals(expected.provideInteger(), b1.a); @@ -90,7 +90,7 @@ public class GenericTest { } @Test public void membersInjections() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); GenericChild childA = new GenericChild(); component.injectA(childA); assertThat(childA.a).isNotNull(); @@ -113,7 +113,7 @@ public class GenericTest { } @Test public void packagePrivateTypeParameterDependencies() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); Exposed exposed = component.exposed(); assertThat(exposed.gpp.t).isNotNull(); assertThat(exposed.gpp2).isNotNull(); @@ -121,13 +121,13 @@ public class GenericTest { @SuppressWarnings("rawtypes") @Test public void publicSubclassWithPackagePrivateTypeParameterOfSuperclass() { - GenericComponent component = Dagger_GenericComponent.create(); + GenericComponent component = DaggerGenericComponent.create(); PublicSubclass publicSubclass = component.publicSubclass(); assertThat(((Generic)publicSubclass).t).isNotNull(); } @Test public void singletonScopesAppliesToEachResolvedType() { - SingletonGenericComponent component = Dagger_SingletonGenericComponent.create(); + SingletonGenericComponent component = DaggerSingletonGenericComponent.create(); ScopedGeneric a = component.scopedGenericA(); assertThat(a).isSameAs(component.scopedGenericA()); assertThat(a.t).isNotNull(); @@ -140,7 +140,7 @@ public class GenericTest { } @Test public void genericModules() { - GenericComponent component = Dagger_GenericComponent.create(); + 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 index 23fb61bb773..04235b68b5a 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/MultibindingTest.java @@ -26,7 +26,7 @@ @RunWith(JUnit4.class) public class MultibindingTest { @Test public void testMultibindings() { - MultibindingComponent multibindingComponent = Dagger_MultibindingComponent.create(); + MultibindingComponent multibindingComponent = DaggerMultibindingComponent.create(); Map map = multibindingComponent.map(); assertThat(map).hasSize(2); assertThat(map).containsEntry("foo", "foo value"); 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 index 157acf999aa..37d3f7aecce 100644 --- a/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java +++ b/compiler/src/it/functional-tests/src/test/java/test/NonComponentDependencyTest.java @@ -25,7 +25,7 @@ public class NonComponentDependencyTest { @Test public void testThing() { NonComponentDependencyComponent component = - Dagger_NonComponentDependencyComponent.builder() + DaggerNonComponentDependencyComponent.builder() .thingComponent(new NonComponentDependencyComponent.ThingComponentImpl()) .build(); assertThat(component).isNotNull(); 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 index 3b1127df530..1b382d8f785 100644 --- 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 @@ -22,14 +22,14 @@ @RunWith(JUnit4.class) public class MembersInjectTest { @Test public void testMembersInject_arrays() { - MembersInjectComponent component = Dagger_MembersInjectComponent.builder().build(); + MembersInjectComponent component = DaggerMembersInjectComponent.builder().build(); ChildOfStringArray childOfStringArray = new ChildOfStringArray(); component.inject(childOfStringArray); } @Test public void testMembersInject_nestedArrays() { - MembersInjectComponent component = Dagger_MembersInjectComponent.builder().build(); + MembersInjectComponent component = DaggerMembersInjectComponent.builder().build(); ChildOfArrayOfParentOfStringArray childOfArrayOfParentOfStringArray = new ChildOfArrayOfParentOfStringArray(); @@ -37,7 +37,7 @@ public class MembersInjectTest { } @Test public void testMembersInject_primitives() { - MembersInjectComponent component = Dagger_MembersInjectComponent.builder().build(); + MembersInjectComponent component = DaggerMembersInjectComponent.builder().build(); ChildOfPrimitiveIntArray childOfPrimitiveIntArray = new ChildOfPrimitiveIntArray(); component.inject(childOfPrimitiveIntArray); 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 index 5ad9efb7c43..a0e1e22f561 100644 --- 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 @@ -26,7 +26,7 @@ public class NullabilityTest { @Test public void testNullability_provides() { NullModule module = new NullModule(); - NullComponent component = Dagger_NullComponent.builder().nullModule(module).build(); + NullComponent component = DaggerNullComponent.builder().nullModule(module).build(); // Can't construct NullFoo because it depends on Number, and Number was null. try { @@ -80,7 +80,7 @@ public class NullabilityTest { } }; NullComponentWithDependency component = - Dagger_NullComponentWithDependency.builder().nullComponent(nullComponent).build(); + DaggerNullComponentWithDependency.builder().nullComponent(nullComponent).build(); validate(false, component.string(), component.stringProvider(), component.numberProvider()); // Also validate that the component's number() method fails 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 index 69fff735e53..c0d01b19ad2 100644 --- 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 @@ -27,7 +27,7 @@ public class SubcomponentTest { @Test public void scopePropagatesUpward_class() { - ParentComponent parentComponent = Dagger_ParentComponent.create(); + ParentComponent parentComponent = DaggerParentComponent.create(); assertThat(parentComponent.newChildComponent().requiresSingleton().singletonType()) .isSameAs(parentComponent.newChildComponent().requiresSingleton().singletonType()); assertThat(parentComponent.newChildComponent().requiresSingleton().singletonType()) @@ -37,7 +37,7 @@ public void scopePropagatesUpward_class() { @Test public void scopePropagatesUpward_provides() { - ParentComponent parentComponent = Dagger_ParentComponent.create(); + ParentComponent parentComponent = DaggerParentComponent.create(); assertThat(parentComponent.newChildComponent() .requiresSingleton().unscopedTypeBoundAsSingleton()) .isSameAs(parentComponent.newChildComponent() @@ -50,7 +50,7 @@ public void scopePropagatesUpward_provides() { @Test public void multibindingContributions() { - ParentComponent parentComponent = Dagger_ParentComponent.create(); + ParentComponent parentComponent = DaggerParentComponent.create(); Set parentObjectSet = parentComponent.objectSet(); assertThat(parentObjectSet).hasSize(2); Set childObjectSet = parentComponent.newChildComponent().objectSet(); @@ -65,7 +65,7 @@ public void multibindingContributions() { @Test public void unscopedProviders() { - ParentComponent parentComponent = Dagger_ParentComponent.create(); + ParentComponent parentComponent = DaggerParentComponent.create(); assertThat(parentComponent.getUnscopedTypeProvider()) .isSameAs(parentComponent.newChildComponent().getUnscopedTypeProvider()); assertThat(parentComponent.getUnscopedTypeProvider()) @@ -76,7 +76,7 @@ public void unscopedProviders() { @Test public void passedModules() { - ParentComponent parentComponent = Dagger_ParentComponent.create(); + ParentComponent parentComponent = DaggerParentComponent.create(); ChildModuleWithState childModuleWithState = new ChildModuleWithState(); ChildComponentRequiringModules childComponent1 = parentComponent.newChildComponentRequiringModules( 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 index 76e916d3eeb..27dcbb69000 100644 --- 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 @@ -24,7 +24,7 @@ @RunWith(JUnit4.class) public class SubcomponentHidingTest { @Test public void moduleNameHiding() { - ParentComponent parent = Dagger_ParentComponent.create(); + 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/producers-functional-tests/src/test/java/test/DependentTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java index 70413ae9459..75c07c7a3dd 100644 --- a/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java +++ b/compiler/src/it/producers-functional-tests/src/test/java/test/DependentTest.java @@ -25,12 +25,12 @@ @RunWith(JUnit4.class) public class DependentTest { @Test public void testDependentComponent() throws Exception { - DependentComponent dependentComponent = Dagger_DependentComponent + DependentComponent dependentComponent = DaggerDependentComponent .builder() - .dependedProductionComponent(Dagger_DependedProductionComponent.builder() + .dependedProductionComponent(DaggerDependedProductionComponent.builder() .executor(MoreExecutors.directExecutor()) .build()) - .dependedComponent(Dagger_DependedComponent.create()) + .dependedComponent(DaggerDependedComponent.create()) .executor(MoreExecutors.directExecutor()) .build(); assertThat(dependentComponent).isNotNull(); diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java index d20de2384b9..20c86dc5254 100644 --- a/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java +++ b/compiler/src/it/producers-functional-tests/src/test/java/test/MultibindingTest.java @@ -25,7 +25,7 @@ @RunWith(JUnit4.class) public class MultibindingTest { @Test public void multibinding() throws Exception { - MultibindingComponent multibindingComponent = Dagger_MultibindingComponent.builder() + MultibindingComponent multibindingComponent = DaggerMultibindingComponent.builder() .executor(MoreExecutors.directExecutor()) .build(); assertThat(multibindingComponent.strs().get()) diff --git a/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java b/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java index de0ea89bdf6..f2b910e3ca8 100644 --- a/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java +++ b/compiler/src/it/producers-functional-tests/src/test/java/test/SimpleTest.java @@ -25,7 +25,7 @@ @RunWith(JUnit4.class) public class SimpleTest { @Test public void testSimpleComponent() throws Exception { - SimpleComponent simpleComponent = Dagger_SimpleComponent + SimpleComponent simpleComponent = DaggerSimpleComponent .builder() .executor(MoreExecutors.directExecutor()) .build(); diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index 412a36fe1b6..f18ae164ca8 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -132,7 +132,7 @@ ClassName nameGeneratedType(BindingGraph input) { ClassName componentDefinitionClassName = ClassName.fromTypeElement(input.componentDescriptor().componentDefinitionType()); String componentName = - "Dagger_" + componentDefinitionClassName.classFileName().replace('$', '_'); + "Dagger" + componentDefinitionClassName.classFileName().replace('$', '_'); return componentDefinitionClassName.topLevelClassName().peerNamed(componentName); } diff --git a/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java index af704ea2fad..1faed549a53 100644 --- a/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/ComponentProcessorTest.java @@ -191,7 +191,7 @@ public class ComponentProcessorTest { " Provider someInjectableTypeProvider();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.Lazy;", @@ -200,8 +200,8 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", - " private Dagger_SimpleComponent(Builder builder) {", + "public final class DaggerSimpleComponent implements SimpleComponent {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -237,7 +237,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -274,7 +274,7 @@ public class ComponentProcessorTest { " Provider someInjectableTypeProvider();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.Lazy;", @@ -284,10 +284,10 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private Provider someInjectableTypeProvider;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -325,7 +325,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -356,7 +356,7 @@ public class ComponentProcessorTest { "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_OuterType_SimpleComponent", + "test.DaggerOuterType_SimpleComponent", "package test;", "", "import dagger.MembersInjector;", @@ -366,10 +366,10 @@ public class ComponentProcessorTest { "import test.OuterType.SimpleComponent;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_OuterType_SimpleComponent implements SimpleComponent {", + "public final class DaggerOuterType_SimpleComponent implements SimpleComponent {", " private MembersInjector bMembersInjector;", "", - " private Dagger_OuterType_SimpleComponent(Builder builder) {", + " private DaggerOuterType_SimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -402,7 +402,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_OuterType_SimpleComponent(this);", + " return new DaggerOuterType_SimpleComponent(this);", " }", " }", "}"); @@ -457,18 +457,18 @@ public class ComponentProcessorTest { " A a();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import javax.annotation.Generated;", "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider bProvider;", " private Provider aProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -502,7 +502,7 @@ public class ComponentProcessorTest { " if (testModule == null) {", " this.testModule = new TestModule();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder testModule(TestModule testModule) {", @@ -592,15 +592,15 @@ public class ComponentProcessorTest { // Generated code includes all includes, but excludes the parent modules. // The "always" module should only be listed once. JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import javax.annotation.Generated;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " }", "", @@ -642,7 +642,7 @@ public class ComponentProcessorTest { " if (parentDepIncluded == null) {", " this.parentDepIncluded = new ParentDepIncluded();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder testModule(TestModule testModule) {", @@ -779,7 +779,7 @@ public class ComponentProcessorTest { " Set strings();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import dagger.internal.SetFactory;", @@ -788,12 +788,12 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider> setOfStringContribution1Provider;", " private Provider> setOfStringContribution2Provider;", " private Provider> setOfStringProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -834,7 +834,7 @@ public class ComponentProcessorTest { " if (setModule == null) {", " this.setModule = new SetModule();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder emptySetModule(EmptySetModule emptySetModule) {", @@ -893,17 +893,17 @@ public class ComponentProcessorTest { " SomeInjectedType injectAndReturn(SomeInjectedType instance);", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.MembersInjector;", "import javax.annotation.Generated;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private MembersInjector someInjectedTypeMembersInjector;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -937,7 +937,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -970,7 +970,7 @@ public class ComponentProcessorTest { " SomeInjectableType someInjectableType();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.internal.InstanceFactory;", @@ -978,11 +978,11 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private Provider simpleComponentProvider;", " private Provider someInjectableTypeProvider;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1011,7 +1011,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -1049,7 +1049,7 @@ public class ComponentProcessorTest { " SomeInjectedType createAndInject();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.MembersInjector;", @@ -1057,11 +1057,11 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private MembersInjector someInjectedTypeMembersInjector;", " private Provider someInjectedTypeProvider;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1091,7 +1091,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -1126,7 +1126,7 @@ public class ComponentProcessorTest { " SomeInjectableType someInjectableType();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import dagger.MembersInjector;", @@ -1135,10 +1135,10 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private Provider someInjectableTypeProvider;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1166,7 +1166,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -1219,7 +1219,7 @@ public class ComponentProcessorTest { " B b();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_BComponent", + "test.DaggerBComponent", "package test;", "", "import dagger.internal.Factory;", @@ -1227,11 +1227,11 @@ public class ComponentProcessorTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_BComponent implements BComponent {", + "public final class DaggerBComponent implements BComponent {", " private Provider aProvider;", " private Provider bProvider;", "", - " private Dagger_BComponent(Builder builder) {", + " private DaggerBComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1268,7 +1268,7 @@ public class ComponentProcessorTest { " if (aComponent == null) {", " throw new IllegalStateException(\"aComponent must be set\");", " }", - " return new Dagger_BComponent(this);", + " return new DaggerBComponent(this);", " }", "", " public Builder aComponent(AComponent aComponent) {", @@ -1331,7 +1331,7 @@ public class ComponentProcessorTest { " other.test.A otherA();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import javax.annotation.Generated;", @@ -1341,11 +1341,11 @@ public class ComponentProcessorTest { "import other.test.TestModule$$AFactory;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider aProvider;", " private Provider aProvider1;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1387,7 +1387,7 @@ public class ComponentProcessorTest { " if (testModule1 == null) {", " this.testModule1 = new TestModule();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder testModule(test.TestModule testModule) {", @@ -1462,19 +1462,19 @@ public class ComponentProcessorTest { " X x();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import javax.annotation.Generated;", "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider bProvider;", " private Provider aProvider;", " private Provider xProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1513,7 +1513,7 @@ public class ComponentProcessorTest { " }", "", " public TestComponent build() {", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", " }", "}"); @@ -1569,14 +1569,14 @@ public class ComponentProcessorTest { "interface SimpleComponent extends SupertypeA, SupertypeB {", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import javax.annotation.Generated;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", - " private Dagger_SimpleComponent(Builder builder) {", + "public final class DaggerSimpleComponent implements SimpleComponent {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1601,7 +1601,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -1657,14 +1657,14 @@ public class ComponentProcessorTest { " SomeInjectableType someInjectableType();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import javax.annotation.Generated;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", - " private Dagger_SimpleComponent(Builder builder) {", + "public final class DaggerSimpleComponent implements SimpleComponent {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -1689,7 +1689,7 @@ public class ComponentProcessorTest { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); @@ -1791,17 +1791,17 @@ public void genericTestToLetMeDebugInEclipse() { " Provider> d2();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_SimpleComponent", + "test.DaggerSimpleComponent", "package test;", "", "import javax.annotation.Generated;", "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_SimpleComponent implements SimpleComponent {", + "public final class DaggerSimpleComponent implements SimpleComponent {", " private Provider dProvider;", "", - " private Dagger_SimpleComponent(Builder builder) {", + " private DaggerSimpleComponent(Builder builder) {", " assert builder != null;", " initialize();", " }", @@ -1828,7 +1828,7 @@ public void genericTestToLetMeDebugInEclipse() { " }", "", " public SimpleComponent build() {", - " return new Dagger_SimpleComponent(this);", + " return new DaggerSimpleComponent(this);", " }", " }", "}"); diff --git a/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java index fccfb3334e7..7593af50714 100644 --- a/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/MapBindingComponentProcessorTest.java @@ -108,7 +108,7 @@ public void mapBindingsWithEnumKey() { "interface TestComponent {", " Map> dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import dagger.internal.MapProviderFactory;", @@ -117,13 +117,13 @@ public void mapBindingsWithEnumKey() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider mapOfPathEnumAndProviderOfHandlerContribution1;", " private Provider mapOfPathEnumAndProviderOfHandlerContribution2;", " private Provider>>", " mapOfPathEnumAndProviderOfHandlerProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -169,7 +169,7 @@ public void mapBindingsWithEnumKey() { " if (mapModuleTwo == null) {", " this.mapModuleTwo = new MapModuleTwo();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModuleOne(MapModuleOne mapModuleOne) {", @@ -276,7 +276,7 @@ public void mapBindingsWithStringKey() { "interface TestComponent {", " Map> dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import dagger.internal.MapProviderFactory;", @@ -285,13 +285,13 @@ public void mapBindingsWithStringKey() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider mapOfStringAndProviderOfHandlerContribution1;", " private Provider mapOfStringAndProviderOfHandlerContribution2;", " private Provider>>", " mapOfStringAndProviderOfHandlerProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -335,7 +335,7 @@ public void mapBindingsWithStringKey() { " if (mapModuleTwo == null) {", " this.mapModuleTwo = new MapModuleTwo();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModuleOne(MapModuleOne mapModuleOne) {", @@ -444,7 +444,7 @@ public void mapBindingsWithNonProviderValue() { "interface TestComponent {", " Map dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import dagger.internal.MapFactory;", @@ -454,14 +454,14 @@ public void mapBindingsWithNonProviderValue() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider mapOfPathEnumAndProviderOfHandlerContribution1;", " private Provider mapOfPathEnumAndProviderOfHandlerContribution2;", " private Provider>>", " mapOfPathEnumAndProviderOfHandlerProvider;", " private Provider> mapOfPathEnumAndHandlerProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -509,7 +509,7 @@ public void mapBindingsWithNonProviderValue() { " if (mapModuleTwo == null) {", " this.mapModuleTwo = new MapModuleTwo();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModuleOne(MapModuleOne mapModuleOne) {", @@ -573,7 +573,7 @@ public void injectMapWithoutMapBinding() { "interface TestComponent {", " Map dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import java.util.Map;", @@ -581,10 +581,10 @@ public void injectMapWithoutMapBinding() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider> provideAMapProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -616,7 +616,7 @@ public void injectMapWithoutMapBinding() { " if (mapModule == null) {", " this.mapModule = new MapModule();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModule(MapModule mapModule) {", diff --git a/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java index 7f0178c85e0..1732b7d58a0 100644 --- a/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/MapKeyProcessorTest.java @@ -149,7 +149,7 @@ public void mapKeyComponentFileWithDisorderedKeyField() { "interface TestComponent {", " Map> dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import dagger.internal.MapProviderFactory;", @@ -158,13 +158,13 @@ public void mapKeyComponentFileWithDisorderedKeyField() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider mapOfPathKeyAndProviderOfHandlerContribution1;", " private Provider mapOfPathKeyAndProviderOfHandlerContribution2;", " private Provider>>", " mapOfPathKeyAndProviderOfHandlerProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -210,7 +210,7 @@ public void mapKeyComponentFileWithDisorderedKeyField() { " if (mapModuleTwo == null) {", " this.mapModuleTwo = new MapModuleTwo();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModuleOne(MapModuleOne mapModuleOne) {", @@ -323,7 +323,7 @@ public void mapKeyComponentFileWithDefaultField() { "interface TestComponent {", " Map> dispatcher();", "}"); - JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.Dagger_TestComponent", + JavaFileObject generatedComponent = JavaFileObjects.forSourceLines("test.DaggerTestComponent", "package test;", "", "import dagger.internal.MapProviderFactory;", @@ -332,13 +332,13 @@ public void mapKeyComponentFileWithDefaultField() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider mapOfPathKeyAndProviderOfHandlerContribution1;", " private Provider mapOfPathKeyAndProviderOfHandlerContribution2;", " private Provider>>", " mapOfPathKeyAndProviderOfHandlerProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -384,7 +384,7 @@ public void mapKeyComponentFileWithDefaultField() { " if (mapModuleTwo == null) {", " this.mapModuleTwo = new MapModuleTwo();", " }", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", "", " public Builder mapModuleOne(MapModuleOne mapModuleOne) {", diff --git a/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java index f02a9fc1f4c..0135e58e882 100644 --- a/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/MembersInjectionTest.java @@ -54,7 +54,7 @@ public void parentClass_noInjectedMembers() { " Child child();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import dagger.MembersInjector;", @@ -63,10 +63,10 @@ public void parentClass_noInjectedMembers() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private Provider childProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -94,7 +94,7 @@ public void parentClass_noInjectedMembers() { " }", "", " public TestComponent build() {", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", " }", "}"); @@ -142,7 +142,7 @@ public void parentClass_injectedMembersInSupertype() { " Child child();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import dagger.MembersInjector;", @@ -151,12 +151,12 @@ public void parentClass_injectedMembersInSupertype() { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private MembersInjector parentMembersInjector;", " private MembersInjector childMembersInjector;", " private Provider childProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -185,7 +185,7 @@ public void parentClass_injectedMembersInSupertype() { " }", "", " public TestComponent build() {", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", " }", "}"); diff --git a/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java b/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java index a387f4221a9..956ff6cbea6 100644 --- a/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/PackageProxyTest.java @@ -59,10 +59,10 @@ public class PackageProxyTest { " PublicClass publicClass();", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", - "import foreign.Dagger_TestComponent__PackageProxy;", + "import foreign.DaggerTestComponent__PackageProxy;", "import foreign.NoDepClass$$Factory;", "import foreign.NonPublicClass1$$Factory;", "import foreign.NonPublicClass2$$Factory;", @@ -72,12 +72,12 @@ public class PackageProxyTest { "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", - " private final Dagger_TestComponent__PackageProxy foreign_Proxy =", - " new Dagger_TestComponent__PackageProxy();", + "public final class DaggerTestComponent implements TestComponent {", + " private final DaggerTestComponent__PackageProxy foreign_Proxy =", + " new DaggerTestComponent__PackageProxy();", " private Provider publicClassProvider;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -111,7 +111,7 @@ public class PackageProxyTest { " }", "", " public TestComponent build() {", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", " }", "}"); @@ -185,25 +185,25 @@ public class PackageProxyTest { " void injectA(A a);", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestComponent", + "test.DaggerTestComponent", "package test;", "", "import dagger.MembersInjector;", "import foreign.B;", "import foreign.B$$MembersInjector;", "import foreign.C$$MembersInjector;", - "import foreign.Dagger_TestComponent__PackageProxy;", + "import foreign.DaggerTestComponent__PackageProxy;", "import javax.annotation.Generated;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestComponent implements TestComponent {", + "public final class DaggerTestComponent implements TestComponent {", " private MembersInjector dMembersInjector;", - " private final Dagger_TestComponent__PackageProxy foreign_Proxy =", - " new Dagger_TestComponent__PackageProxy();", + " private final DaggerTestComponent__PackageProxy foreign_Proxy =", + " new DaggerTestComponent__PackageProxy();", " private MembersInjector bMembersInjector;", " private MembersInjector aMembersInjector;", "", - " private Dagger_TestComponent(Builder builder) {", + " private DaggerTestComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -236,7 +236,7 @@ public class PackageProxyTest { " }", "", " public TestComponent build() {", - " return new Dagger_TestComponent(this);", + " return new DaggerTestComponent(this);", " }", " }", "}"); diff --git a/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java index 381251de32d..d30800df4e2 100644 --- a/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/ProductionComponentProcessorTest.java @@ -124,7 +124,7 @@ public class ProductionComponentProcessorTest { " }", "}"); JavaFileObject generatedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_TestClass_SimpleComponent", + "test.DaggerTestClass_SimpleComponent", "package test;", "", "import com.google.common.util.concurrent.ListenableFuture;", @@ -140,11 +140,11 @@ public class ProductionComponentProcessorTest { "import test.TestClass.SimpleComponent;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_TestClass_SimpleComponent implements SimpleComponent {", + "public final class DaggerTestClass_SimpleComponent implements SimpleComponent {", " private Provider bProvider;", " private Producer aProducer;", "", - " private Dagger_TestClass_SimpleComponent(Builder builder) {", + " private DaggerTestClass_SimpleComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -183,7 +183,7 @@ public class ProductionComponentProcessorTest { " if (executor == null) {", " throw new IllegalStateException(\"executor must be set\");", " }", - " return new Dagger_TestClass_SimpleComponent(this);", + " return new DaggerTestClass_SimpleComponent(this);", " }", "", " public Builder aModule(AModule aModule) {", diff --git a/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java index 4def47a1e86..26c8e4e8cf2 100644 --- a/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java +++ b/compiler/src/test/java/dagger/tests/integration/operation/PrimitiveInjectionTest.java @@ -68,18 +68,18 @@ public final class PrimitiveInjectionTest { "}"); JavaFileObject expectedComponent = JavaFileObjects.forSourceLines( - "test.Dagger_PrimitiveComponent", + "test.DaggerPrimitiveComponent", "package test;", "", "import javax.annotation.Generated;", "import javax.inject.Provider;", "", "@Generated(\"dagger.internal.codegen.ComponentProcessor\")", - "public final class Dagger_PrimitiveComponent implements PrimitiveComponent {", + "public final class DaggerPrimitiveComponent implements PrimitiveComponent {", " private Provider primitiveIntProvider;", " private Provider primitiveInjectableProvider;", "", - " private Dagger_PrimitiveComponent(Builder builder) {", + " private DaggerPrimitiveComponent(Builder builder) {", " assert builder != null;", " initialize(builder);", " }", @@ -119,7 +119,7 @@ public final class PrimitiveInjectionTest { " if (primitiveModule == null) {", " this.primitiveModule = new PrimitiveModule();", " }", - " return new Dagger_PrimitiveComponent(this);", + " return new DaggerPrimitiveComponent(this);", " }", "", " public Builder primitiveModule(PrimitiveModule primitiveModule) {", diff --git a/core/src/main/java/dagger/Component.java b/core/src/main/java/dagger/Component.java index eb0344749f2..637f60203cb 100644 --- a/core/src/main/java/dagger/Component.java +++ b/core/src/main/java/dagger/Component.java @@ -29,8 +29,8 @@ * 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 Dagger_MyComponent}. + * {@code Dagger}. For example, {@code @Component interface MyComponent {...}} will + * produce an implementation named {@code DaggerMyComponent}. * *

Component methods

* 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 index 23ac08fd8ea..72057332ccc 100644 --- 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 @@ -28,7 +28,7 @@ public class DemoApplication extends Application { @Override public void onCreate() { super.onCreate(); - applicationComponent = Dagger_ApplicationComponent.builder() + applicationComponent = DaggerApplicationComponent.builder() .demoApplicationModule(new DemoApplicationModule(this)) .build(); } 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 index f0bd87815a1..1f3bb7002e2 100644 --- 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 @@ -28,7 +28,7 @@ public class HomeActivity extends FragmentActivity { HomeComponent component() { if (component == null) { - component = Dagger_HomeComponent.builder() + component = DaggerHomeComponent.builder() .applicationComponent(((DemoApplication) getApplication()).component()) .activityModule(new ActivityModule(this)) .build(); 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 index 0a08d987bf9..55402c65490 100644 --- 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 @@ -40,7 +40,7 @@ public interface ApplicationComponent { @Override public void onCreate() { super.onCreate(); - component = Dagger_DemoApplication_ApplicationComponent.builder() + component = DaggerDemoApplication_ApplicationComponent.builder() .androidModule(new AndroidModule(this)) .build(); component().inject(this); // As of now, LocationManager should be injected into this. diff --git a/examples/simple/src/main/java/coffee/CoffeeApp.java b/examples/simple/src/main/java/coffee/CoffeeApp.java index 0789a86f10b..b0a93ec3c49 100644 --- a/examples/simple/src/main/java/coffee/CoffeeApp.java +++ b/examples/simple/src/main/java/coffee/CoffeeApp.java @@ -11,7 +11,7 @@ public interface Coffee { } public static void main(String[] args) { - Coffee coffee = Dagger_CoffeeApp_Coffee.builder().build(); + Coffee coffee = DaggerCoffeeApp_Coffee.builder().build(); coffee.maker().brew(); } } diff --git a/producers/src/main/java/dagger/producers/Producer.java b/producers/src/main/java/dagger/producers/Producer.java index cccf783766c..fdf7dddcf00 100644 --- a/producers/src/main/java/dagger/producers/Producer.java +++ b/producers/src/main/java/dagger/producers/Producer.java @@ -65,7 +65,7 @@ * Suppose we instantiate the generated implementation of this component and call * {@code delayedC()}:
   {@code
  *
- *   MyComponent component = Dagger_MyComponent
+ *   MyComponent component = DaggerMyComponent
  *       .builder()
  *       .executor(MoreExecutors.directExecutor())
  *       .build();
diff --git a/producers/src/main/java/dagger/producers/ProductionComponent.java b/producers/src/main/java/dagger/producers/ProductionComponent.java
index b6376b0b047..02ba7c879db 100644
--- a/producers/src/main/java/dagger/producers/ProductionComponent.java
+++ b/producers/src/main/java/dagger/producers/ProductionComponent.java
@@ -29,8 +29,8 @@
  * 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 Dagger_MyComponent}.
+ * {@code Dagger}.  For example, {@code @ProductionComponent interface MyComponent {...}} will
+ * produce an implementation named {@code DaggerMyComponent}.
  *
  * 

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. From a1905a26ac3b125c2e8db20481d9a84d01bdc551 Mon Sep 17 00:00:00 2001 From: gak Date: Thu, 2 Apr 2015 22:49:00 -0700 Subject: [PATCH 08/16] Add a package-info.java for dagger. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90228800 --- core/src/main/java/dagger/package-info.java | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 core/src/main/java/dagger/package-info.java 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 00000000000..e5cc67f39ef --- /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 Dagger + * 2 dependency injection framework. By building upon + * JSR 330, Dagger 2 provides an + * annotation-driven API for dependency injection whose implementation is entirely generated at + * compile time by annotation + * processors. + * + *

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}. + * + *

{@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; From 6322fe75a3222e09b859382a857496f7b835e0e3 Mon Sep 17 00:00:00 2001 From: gak Date: Fri, 3 Apr 2015 14:57:16 -0700 Subject: [PATCH 09/16] Add tests for providing all of the framework types and rework the infrastructure that detects it to ensure consistent behavior. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90283952 --- .../src/main/java/test/BasicComponent.java | 7 ++ .../src/main/java/test/InjectedThing.java | 6 +- .../dagger/internal/codegen/BindingGraph.java | 36 +----- .../codegen/BindingGraphValidator.java | 10 +- .../internal/codegen/ComponentDescriptor.java | 109 +++++++++++------ .../internal/codegen/ComponentGenerator.java | 114 ++++++++++-------- .../internal/codegen/ComponentProcessor.java | 2 +- .../internal/codegen/DependencyRequest.java | 24 +++- 8 files changed, 182 insertions(+), 126 deletions(-) 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 index 0f8fe75bb85..9ee15b5d2f0 100644 --- a/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java +++ b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java @@ -16,6 +16,8 @@ package test; import dagger.Component; +import dagger.Lazy; +import dagger.MembersInjector; import javax.inject.Provider; @Component(modules = PrimitivesModule.class) @@ -69,6 +71,11 @@ interface BasicComponent { Thing thing(); InjectedThing injectedThing(); + Provider injectedThingProvider(); + Lazy lazyInjectedThing(); + MembersInjector injectedThingMembersInjector(); TypeWithInheritedMembersInjection typeWithInheritedMembersInjection(); + MembersInjector + typeWithInheritedMembersInjectionMembersInjector(); } 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 index a28a6ff2d55..73a46e8aa20 100644 --- a/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java +++ b/compiler/src/it/functional-tests/src/main/java/test/InjectedThing.java @@ -16,6 +16,7 @@ package test; import dagger.Lazy; +import dagger.MembersInjector; import javax.inject.Inject; import javax.inject.Provider; @@ -87,6 +88,7 @@ final class InjectedThing { @Inject Thing thing; @Inject Provider thingProvider; @Inject Lazy lazyThing; + @Inject MembersInjector thingMembersInjector; @Inject InjectedThing( byte primitiveByte, @@ -154,7 +156,8 @@ final class InjectedThing { Thing thing, Provider thingProvider, - Lazy lazyThing) {} + Lazy lazyThing, + MembersInjector thingMembersInjector) {} @Inject void primitiveByte(byte primitiveByte) {} @Inject void primitiveChar(char primitiveChar) {} @@ -222,4 +225,5 @@ final class InjectedThing { @Inject void thing(Thing thing) {} @Inject void thingProvider(Provider thingProvider) {} @Inject void lazyThing(Lazy lazyThing) {} + @Inject void thingMembersInjector(MembersInjector thingMembersInjector) {} } diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java index a2926cc22d2..69c9b3d744d 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraph.java @@ -29,7 +29,7 @@ import com.google.common.collect.Sets; import dagger.Component; import dagger.Provides; -import dagger.internal.codegen.ComponentDescriptor.ComponentMethodType; +import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; import dagger.producers.Produces; import dagger.producers.ProductionComponent; import java.util.Deque; @@ -71,7 +71,6 @@ enum ModuleStrategy { } abstract ComponentDescriptor componentDescriptor(); - abstract ImmutableSet entryPoints(); abstract ImmutableMap transitiveModules(); abstract ImmutableMap resolvedBindings(); abstract ImmutableMap subgraphs(); @@ -223,13 +222,11 @@ && isComponentProductionMethod(elements, method)) { componentDescriptor.wrappedScope(), explicitBindingsByKey(explicitProvisionBindingsBuilder.build()), explicitBindingsByKey(explicitProductionBindingsBuilder.build())); - ImmutableSetMultimap componentMethods = - componentDescriptor.componentMethods(); - - ImmutableSet componentMethodRequests = - componentMethodRequests(componentMethods); - for (DependencyRequest componentMethodRequest : componentMethodRequests) { - requestResolver.resolve(componentMethodRequest); + for (ComponentMethodDescriptor componentMethod : componentDescriptor.componentMethods()) { + Optional componentMethodRequest = componentMethod.dependencyRequest(); + if (componentMethodRequest.isPresent()) { + requestResolver.resolve(componentMethodRequest.get()); + } } ImmutableMap.Builder subgraphsBuilder = @@ -242,7 +239,6 @@ && isComponentProductionMethod(elements, method)) { return new AutoValue_BindingGraph( componentDescriptor, - componentMethodRequests, transitiveModules.build(), requestResolver.getResolvedBindings(), subgraphsBuilder.build()); @@ -258,26 +254,6 @@ private ImmutableSetMultimap explicitBin return builder.build(); } - private ImmutableSet componentMethodRequests( - ImmutableSetMultimap componentMethods) { - ImmutableSet.Builder interfaceRequestsBuilder = ImmutableSet.builder(); - for (ExecutableElement provisionMethod : componentMethods.get(ComponentMethodType.PROVISON)) { - interfaceRequestsBuilder.add( - dependencyRequestFactory.forComponentProvisionMethod(provisionMethod)); - } - for (ExecutableElement productionMethod : - componentMethods.get(ComponentMethodType.PRODUCTION)) { - interfaceRequestsBuilder.add( - dependencyRequestFactory.forComponentProductionMethod(productionMethod)); - } - for (ExecutableElement membersInjectionMethod : - componentMethods.get(ComponentMethodType.MEMBERS_INJECTION)) { - interfaceRequestsBuilder.add( - dependencyRequestFactory.forComponentMembersInjectionMethod(membersInjectionMethod)); - } - return interfaceRequestsBuilder.build(); - } - private final class RequestResolver { final Optional parentResolver; final Optional> targetScope; diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java index a1e0b69621e..e886353edc6 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java @@ -35,6 +35,7 @@ import com.google.common.collect.Sets; import dagger.Component; import dagger.internal.codegen.BindingGraph.ResolvedBindings; +import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; import dagger.internal.codegen.ContributionBinding.BindingType; import dagger.internal.codegen.ValidationReport.Builder; import dagger.internal.codegen.writer.TypeNames; @@ -117,8 +118,13 @@ private ValidationReport validate(final BindingGraph subject, validateComponentScope(subject, reportBuilder, resolvedBindings); validateDependencyScopes(subject, reportBuilder); - for (DependencyRequest entryPoint : subject.entryPoints()) { - traverseRequest(entryPoint, new ArrayDeque(), subject, reportBuilder); + for (ComponentMethodDescriptor componentMethod : + subject.componentDescriptor().componentMethods()) { + Optional entryPoint = componentMethod.dependencyRequest(); + if (entryPoint.isPresent()) { + traverseRequest(entryPoint.get(), new ArrayDeque(), subject, + reportBuilder); + } } validateSubcomponents(subject, reportBuilder); diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java index e2a2eb605c7..218e3b34066 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java @@ -23,16 +23,18 @@ import com.google.common.base.Optional; 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.util.concurrent.ListenableFuture; import dagger.Component; +import dagger.Lazy; +import dagger.MembersInjector; import dagger.Subcomponent; import dagger.producers.ProductionComponent; import java.lang.annotation.Annotation; import java.util.Iterator; import java.util.List; 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.Modifier; @@ -120,9 +122,16 @@ Optional scope() { abstract ImmutableMap subcomponents(); - abstract ImmutableSetMultimap componentMethods(); + abstract ImmutableSet componentMethods(); - enum ComponentMethodType { + @AutoValue + static abstract class ComponentMethodDescriptor { + abstract ComponentMethodKind kind(); + abstract Optional dependencyRequest(); + abstract ExecutableElement methodElement(); + } + + enum ComponentMethodKind { PROVISON, PRODUCTION, MEMBERS_INJECTION, @@ -131,9 +140,11 @@ enum ComponentMethodType { static final class Factory { private final Elements elements; + private final DependencyRequest.Factory dependencyRequestFactory; - Factory(Elements elements) { + Factory(Elements elements, DependencyRequest.Factory dependencyRequestFactory) { this.elements = elements; + this.dependencyRequestFactory = dependencyRequestFactory; } ComponentDescriptor forComponent(TypeElement componentDefinitionType) { @@ -175,16 +186,16 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin ImmutableSet unimplementedMethods = getUnimplementedMethods(elements, componentDefinitionType); - ImmutableSetMultimap.Builder componentMethodsBuilder = - ImmutableSetMultimap.builder(); + ImmutableSet.Builder componentMethodsBuilder = + ImmutableSet.builder(); ImmutableMap.Builder subcomponentDescriptors = ImmutableMap.builder(); for (ExecutableElement componentMethod : unimplementedMethods) { - ComponentMethodType componentMethodType = - getComponentMethodType(kind, componentMethod); - componentMethodsBuilder.put(componentMethodType, componentMethod); - if (componentMethodType.equals(ComponentMethodType.SUBCOMPONENT)) { + ComponentMethodDescriptor componentMethodDescriptor = + getDescriptorForComponentMethod(kind, componentMethod); + componentMethodsBuilder.add(componentMethodDescriptor); + if (componentMethodDescriptor.kind().equals(ComponentMethodKind.SUBCOMPONENT)) { subcomponentDescriptors.put(componentMethod, create(MoreElements.asType(MoreTypes.asElement(componentMethod.getReturnType())), Kind.COMPONENT)); @@ -203,36 +214,64 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin subcomponentDescriptors.build(), componentMethodsBuilder.build()); } - } - private static ComponentMethodType getComponentMethodType(Kind componentKind, - ExecutableElement method) { - TypeMirror returnType = method.getReturnType(); - if (returnType.getKind().equals(DECLARED) && - getAnnotationMirror(MoreTypes.asElement(returnType), Subcomponent.class).isPresent()) { - return ComponentMethodType.SUBCOMPONENT; - } + private ComponentMethodDescriptor getDescriptorForComponentMethod(Kind componentKind, + ExecutableElement componentMethod) { + TypeMirror returnType = componentMethod.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)), + componentMethod); + } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) { + return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( + ComponentMethodKind.MEMBERS_INJECTION, + Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod( + componentMethod)), + componentMethod); + } else if (getAnnotationMirror(MoreTypes.asElement(returnType), Subcomponent.class) + .isPresent()) { + return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( + ComponentMethodKind.SUBCOMPONENT, + Optional.absent(), + componentMethod); + } + } - if (method.getParameters().isEmpty() - && !method.getReturnType().getKind().equals(VOID)) { - switch (componentKind) { - case COMPONENT: - return ComponentMethodType.PROVISON; - case PRODUCTION_COMPONENT: - return ComponentMethodType.PRODUCTION; - default: - throw new AssertionError(); + // a typical provision method + if (componentMethod.getParameters().isEmpty() + && !componentMethod.getReturnType().getKind().equals(VOID)) { + switch (componentKind) { + case COMPONENT: + return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( + ComponentMethodKind.PROVISON, + Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod)), + componentMethod); + case PRODUCTION_COMPONENT: + return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( + ComponentMethodKind.PRODUCTION, + Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod)), + componentMethod); + default: + throw new AssertionError(); + } } - } - List parameters = method.getParameters(); - if (parameters.size() == 1 - && (returnType.getKind().equals(VOID) - || MoreTypes.equivalence().equivalent(returnType, parameters.get(0).asType()))) { - return ComponentMethodType.MEMBERS_INJECTION; - } + List parameters = componentMethod.getParameters(); + if (parameters.size() == 1 + && (returnType.getKind().equals(VOID) + || MoreTypes.equivalence().equivalent(returnType, parameters.get(0).asType()))) { + return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( + ComponentMethodKind.MEMBERS_INJECTION, + Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod( + componentMethod)), + componentMethod); + } - throw new IllegalArgumentException(); + throw new IllegalArgumentException("not a valid component method: " + componentMethod); + } } static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) { diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index f18ae164ca8..17d079c10c9 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -46,6 +46,7 @@ import dagger.internal.ScopedProvider; import dagger.internal.SetFactory; import dagger.internal.codegen.BindingGraph.ResolvedBindings; +import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor; import dagger.internal.codegen.ContributionBinding.BindingType; import dagger.internal.codegen.writer.ClassName; import dagger.internal.codegen.writer.ClassWriter; @@ -655,63 +656,74 @@ private void writeInterfaceMethods(BindingGraph input, ClassWriter componentWrit ImmutableSet enumBindingKeys) throws AssertionError { Set interfaceMethods = Sets.newHashSet(); - for (DependencyRequest interfaceRequest : input.entryPoints()) { - ExecutableElement requestElement = - MoreElements.asExecutable(interfaceRequest.requestElement()); - MethodSignature signature = MethodSignature.fromExecutableElement(requestElement); - if (!interfaceMethods.contains(signature)) { - interfaceMethods.add(signature); - MethodWriter interfaceMethod = requestElement.getReturnType().getKind().equals(VOID) - ? componentWriter.addMethod(VoidName.VOID, requestElement.getSimpleName().toString()) - : componentWriter.addMethod(requestElement.getReturnType(), - requestElement.getSimpleName().toString()); - interfaceMethod.annotate(Override.class); - interfaceMethod.addModifiers(PUBLIC); - BindingKey bindingKey = interfaceRequest.bindingKey(); - switch(interfaceRequest.kind()) { - case MEMBERS_INJECTOR: - MemberSelect membersInjectorSelect = memberSelectSnippets.get(bindingKey); - VariableElement parameter = Iterables.getOnlyElement(requestElement.getParameters()); - Name parameterName = parameter.getSimpleName(); - interfaceMethod.addParameter( - TypeNames.forTypeMirror(parameter.asType()), parameterName.toString()); - interfaceMethod.body() + for (ComponentMethodDescriptor componentMethod : + input.componentDescriptor().componentMethods()) { + if (componentMethod.dependencyRequest().isPresent()) { + DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get(); + ExecutableElement requestElement = + MoreElements.asExecutable(interfaceRequest.requestElement()); + MethodSignature signature = MethodSignature.fromExecutableElement(requestElement); + if (!interfaceMethods.contains(signature)) { + interfaceMethods.add(signature); + MethodWriter interfaceMethod = requestElement.getReturnType().getKind().equals(VOID) + ? componentWriter.addMethod(VoidName.VOID, requestElement.getSimpleName().toString()) + : componentWriter.addMethod(requestElement.getReturnType(), + requestElement.getSimpleName().toString()); + interfaceMethod.annotate(Override.class); + interfaceMethod.addModifiers(PUBLIC); + BindingKey bindingKey = interfaceRequest.bindingKey(); + switch(interfaceRequest.kind()) { + case MEMBERS_INJECTOR: + MemberSelect membersInjectorSelect = memberSelectSnippets.get(bindingKey); + List parameters = requestElement.getParameters(); + if (parameters.isEmpty()) { + // we're returning the framework type + interfaceMethod.body().addSnippet("return %s;", + membersInjectorSelect.getSnippetFor(componentWriter.name())); + } else { + VariableElement parameter = Iterables.getOnlyElement(parameters); + Name parameterName = parameter.getSimpleName(); + interfaceMethod.addParameter( + TypeNames.forTypeMirror(parameter.asType()), parameterName.toString()); + interfaceMethod.body() .addSnippet("%s.injectMembers(%s);", // in this case we know we won't need the cast because we're never going to pass // the reference to anything membersInjectorSelect.getSnippetFor(componentWriter.name()), parameterName); - if (!requestElement.getReturnType().getKind().equals(VOID)) { - interfaceMethod.body().addSnippet("return %s;", parameterName); - } - break; - case INSTANCE: - if (enumBindingKeys.contains(bindingKey) - && !MoreTypes.asDeclared(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(requestElement.getReturnType())); - interfaceMethod.body().addSnippet("%s factory = %s;", factoryType, - memberSelectSnippets.get(bindingKey).getSnippetFor(componentWriter.name())); - interfaceMethod.body().addSnippet("return factory.get();"); + if (!requestElement.getReturnType().getKind().equals(VOID)) { + interfaceMethod.body().addSnippet("return %s;", parameterName); + } + } break; - } - // fall through in the else case. - case LAZY: - case PRODUCED: - case PRODUCER: - case PROVIDER: - case FUTURE: - interfaceMethod.body().addSnippet("return %s;", - frameworkTypeUsageStatement( - memberSelectSnippets.get(bindingKey).getSnippetFor(componentWriter.name()), - interfaceRequest.kind())); - break; - default: - throw new AssertionError(); + case INSTANCE: + if (enumBindingKeys.contains(bindingKey) + && !MoreTypes.asDeclared(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(requestElement.getReturnType())); + interfaceMethod.body().addSnippet("%s factory = %s;", factoryType, + memberSelectSnippets.get(bindingKey).getSnippetFor(componentWriter.name())); + 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( + memberSelectSnippets.get(bindingKey).getSnippetFor(componentWriter.name()), + interfaceRequest.kind())); + break; + default: + throw new AssertionError(); + } } } } diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java index 86c4ffa89b5..fa18be53d0a 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java @@ -117,7 +117,7 @@ protected Iterable initSteps() { membersInjectionBindingFactory, membersInjectorGenerator); ComponentDescriptor.Factory componentDescriptorFactory = - new ComponentDescriptor.Factory(elements); + new ComponentDescriptor.Factory(elements, dependencyRequestFactory); BindingGraph.Factory bindingGraphFactory = new BindingGraph.Factory( elements, types, injectBindingRegistry, keyFactory, diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java index 9e36418fd7b..9b42030e8be 100644 --- a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java +++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java @@ -44,6 +44,7 @@ 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; /** * Represents a request for a key at an injection point. Parameters to {@link Inject} constructors @@ -200,12 +201,23 @@ DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersIn Optional qualifier = InjectionAnnotations.getQualifier(membersInjectionMethod); checkArgument(!qualifier.isPresent()); - return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR, - keyFactory.forMembersInjectedType( - Iterables.getOnlyElement(membersInjectionMethod.getParameters()).asType()), - membersInjectionMethod, - getEnclosingType(membersInjectionMethod), - false /* doesn't allow null */); + TypeMirror returnType = membersInjectionMethod.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 */); + } else { + return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR, + keyFactory.forMembersInjectedType( + Iterables.getOnlyElement(membersInjectionMethod.getParameters()).asType()), + membersInjectionMethod, + getEnclosingType(membersInjectionMethod), + false /* doesn't allow null */); + } } DependencyRequest forMembersInjectedType(DeclaredType type) { From f781e326989e219befe4c29306683c60922aec54 Mon Sep 17 00:00:00 2001 From: gak Date: Fri, 3 Apr 2015 16:12:07 -0700 Subject: [PATCH 10/16] Ensure that generics are resolved in components. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90290342 --- .../src/main/java/test/BasicComponent.java | 2 +- .../src/main/java/test/Injector.java | 32 ++++++++++++++++ .../internal/codegen/ComponentDescriptor.java | 37 ++++++++++++------- .../internal/codegen/ComponentGenerator.java | 23 ++++++++---- .../internal/codegen/ComponentProcessor.java | 2 +- .../internal/codegen/DependencyRequest.java | 22 +++++++---- .../internal/codegen/MethodSignature.java | 15 ++++---- 7 files changed, 94 insertions(+), 39 deletions(-) create mode 100644 compiler/src/it/functional-tests/src/main/java/test/Injector.java 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 index 9ee15b5d2f0..a04607dd451 100644 --- a/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java +++ b/compiler/src/it/functional-tests/src/main/java/test/BasicComponent.java @@ -21,7 +21,7 @@ import javax.inject.Provider; @Component(modules = PrimitivesModule.class) -interface BasicComponent { +interface BasicComponent extends Injector { byte getByte(); char getChar(); short getShort(); 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 00000000000..2a5798a03df --- /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 instance(); + Provider provider(); + Lazy lazy(); + MembersInjector membersInjector(); + void injectMembers(T t); + T injectMembersAndReturn(T t); +} diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java index 218e3b34066..03f759a2ef0 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java @@ -39,11 +39,12 @@ 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.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.getAnnotationMirror; import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies; @@ -140,10 +141,12 @@ enum ComponentMethodKind { static final class Factory { private final Elements elements; + private final Types types; private final DependencyRequest.Factory dependencyRequestFactory; - Factory(Elements elements, DependencyRequest.Factory dependencyRequestFactory) { + Factory(Elements elements, Types types, DependencyRequest.Factory dependencyRequestFactory) { this.elements = elements; + this.types = types; this.dependencyRequestFactory = dependencyRequestFactory; } @@ -193,7 +196,7 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin ImmutableMap.builder(); for (ExecutableElement componentMethod : unimplementedMethods) { ComponentMethodDescriptor componentMethodDescriptor = - getDescriptorForComponentMethod(kind, componentMethod); + getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod); componentMethodsBuilder.add(componentMethodDescriptor); if (componentMethodDescriptor.kind().equals(ComponentMethodKind.SUBCOMPONENT)) { subcomponentDescriptors.put(componentMethod, @@ -215,21 +218,26 @@ private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kin componentMethodsBuilder.build()); } - private ComponentMethodDescriptor getDescriptorForComponentMethod(Kind componentKind, + private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement, + Kind componentKind, ExecutableElement componentMethod) { - TypeMirror returnType = componentMethod.getReturnType(); + 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)), + 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)), + componentMethod, + resolvedComponentMethod)), componentMethod); } else if (getAnnotationMirror(MoreTypes.asElement(returnType), Subcomponent.class) .isPresent()) { @@ -247,26 +255,29 @@ private ComponentMethodDescriptor getDescriptorForComponentMethod(Kind component case COMPONENT: return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( ComponentMethodKind.PROVISON, - Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod)), + Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod, + resolvedComponentMethod)), componentMethod); case PRODUCTION_COMPONENT: return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( ComponentMethodKind.PRODUCTION, - Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod)), + Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod, + resolvedComponentMethod)), componentMethod); default: throw new AssertionError(); } } - List parameters = componentMethod.getParameters(); - if (parameters.size() == 1 + List parameterTypes = resolvedComponentMethod.getParameterTypes(); + if (parameterTypes.size() == 1 && (returnType.getKind().equals(VOID) - || MoreTypes.equivalence().equivalent(returnType, parameters.get(0).asType()))) { + || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) { return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor( ComponentMethodKind.MEMBERS_INJECTION, Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod( - componentMethod)), + componentMethod, + resolvedComponentMethod)), componentMethod); } diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java index 17d079c10c9..2a9f434a7db 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentGenerator.java @@ -84,6 +84,7 @@ 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.SimpleAnnotationValueVisitor6; @@ -662,12 +663,17 @@ private void writeInterfaceMethods(BindingGraph input, ClassWriter componentWrit DependencyRequest interfaceRequest = componentMethod.dependencyRequest().get(); ExecutableElement requestElement = MoreElements.asExecutable(interfaceRequest.requestElement()); - MethodSignature signature = MethodSignature.fromExecutableElement(requestElement); + ExecutableType requestType = MoreTypes.asExecutable(types.asMemberOf( + MoreTypes.asDeclared(input.componentDescriptor().componentDefinitionType().asType()), + requestElement)); + MethodSignature signature = MethodSignature.fromExecutableType( + requestElement.getSimpleName().toString(), + requestType); if (!interfaceMethods.contains(signature)) { interfaceMethods.add(signature); - MethodWriter interfaceMethod = requestElement.getReturnType().getKind().equals(VOID) + MethodWriter interfaceMethod = requestType.getReturnType().getKind().equals(VOID) ? componentWriter.addMethod(VoidName.VOID, requestElement.getSimpleName().toString()) - : componentWriter.addMethod(requestElement.getReturnType(), + : componentWriter.addMethod(requestType.getReturnType(), requestElement.getSimpleName().toString()); interfaceMethod.annotate(Override.class); interfaceMethod.addModifiers(PUBLIC); @@ -684,14 +690,15 @@ private void writeInterfaceMethods(BindingGraph input, ClassWriter componentWrit VariableElement parameter = Iterables.getOnlyElement(parameters); Name parameterName = parameter.getSimpleName(); interfaceMethod.addParameter( - TypeNames.forTypeMirror(parameter.asType()), parameterName.toString()); - interfaceMethod.body() - .addSnippet("%s.injectMembers(%s);", + TypeNames.forTypeMirror( + Iterables.getOnlyElement(requestType.getParameterTypes())), + parameterName.toString()); + interfaceMethod.body().addSnippet("%s.injectMembers(%s);", // in this case we know we won't need the cast because we're never going to pass // the reference to anything membersInjectorSelect.getSnippetFor(componentWriter.name()), parameterName); - if (!requestElement.getReturnType().getKind().equals(VOID)) { + if (!requestType.getReturnType().getKind().equals(VOID)) { interfaceMethod.body().addSnippet("return %s;", parameterName); } } @@ -704,7 +711,7 @@ private void writeInterfaceMethods(BindingGraph input, ClassWriter componentWrit // 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(requestElement.getReturnType())); + TypeNames.forTypeMirror(requestType.getReturnType())); interfaceMethod.body().addSnippet("%s factory = %s;", factoryType, memberSelectSnippets.get(bindingKey).getSnippetFor(componentWriter.name())); interfaceMethod.body().addSnippet("return factory.get();"); diff --git a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java index fa18be53d0a..401681c7242 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ComponentProcessor.java @@ -117,7 +117,7 @@ protected Iterable initSteps() { membersInjectionBindingFactory, membersInjectorGenerator); ComponentDescriptor.Factory componentDescriptorFactory = - new ComponentDescriptor.Factory(elements, dependencyRequestFactory); + new ComponentDescriptor.Factory(elements, types, dependencyRequestFactory); BindingGraph.Factory bindingGraphFactory = new BindingGraph.Factory( elements, types, injectBindingRegistry, keyFactory, diff --git a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java index 9b42030e8be..2fbb507c200 100644 --- a/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java +++ b/compiler/src/main/java/dagger/internal/codegen/DependencyRequest.java @@ -37,6 +37,7 @@ 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.TypeKind; import javax.lang.model.type.TypeMirror; @@ -164,21 +165,24 @@ DependencyRequest forRequiredResolvedVariable(DeclaredType container, return newDependencyRequest(variableElement, resolvedType, qualifier, container); } - DependencyRequest forComponentProvisionMethod(ExecutableElement provisionMethod) { + DependencyRequest forComponentProvisionMethod(ExecutableElement provisionMethod, + ExecutableType provisionMethodType) { checkNotNull(provisionMethod); + checkNotNull(provisionMethodType); checkArgument(provisionMethod.getParameters().isEmpty(), "Component provision methods must be empty: " + provisionMethod); - TypeMirror type = provisionMethod.getReturnType(); Optional qualifier = InjectionAnnotations.getQualifier(provisionMethod); - return newDependencyRequest(provisionMethod, type, qualifier, + return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier, getEnclosingType(provisionMethod)); } - DependencyRequest forComponentProductionMethod(ExecutableElement productionMethod) { + DependencyRequest forComponentProductionMethod(ExecutableElement productionMethod, + ExecutableType productionMethodType) { checkNotNull(productionMethod); + checkNotNull(productionMethodType); checkArgument(productionMethod.getParameters().isEmpty(), "Component production methods must be empty: %s", productionMethod); - TypeMirror type = productionMethod.getReturnType(); + TypeMirror type = productionMethodType.getReturnType(); Optional qualifier = InjectionAnnotations.getQualifier(productionMethod); DeclaredType container = getEnclosingType(productionMethod); // Only a component production method can be a request for a ListenableFuture, so we @@ -196,12 +200,14 @@ DependencyRequest forComponentProductionMethod(ExecutableElement productionMetho } } - DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod) { + DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod, + ExecutableType membersInjectionMethodType) { checkNotNull(membersInjectionMethod); + checkNotNull(membersInjectionMethodType); Optional qualifier = InjectionAnnotations.getQualifier(membersInjectionMethod); checkArgument(!qualifier.isPresent()); - TypeMirror returnType = membersInjectionMethod.getReturnType(); + TypeMirror returnType = membersInjectionMethodType.getReturnType(); if (returnType.getKind().equals(DECLARED) && MoreTypes.isTypeOf(MembersInjector.class, returnType)) { return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR, @@ -213,7 +219,7 @@ DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersIn } else { return new AutoValue_DependencyRequest(Kind.MEMBERS_INJECTOR, keyFactory.forMembersInjectedType( - Iterables.getOnlyElement(membersInjectionMethod.getParameters()).asType()), + Iterables.getOnlyElement(membersInjectionMethodType.getParameterTypes())), membersInjectionMethod, getEnclosingType(membersInjectionMethod), false /* doesn't allow null */); diff --git a/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java index d45fd875899..447ed24ef39 100644 --- a/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java +++ b/compiler/src/main/java/dagger/internal/codegen/MethodSignature.java @@ -4,8 +4,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Equivalence; import com.google.common.collect.ImmutableList; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeMirror; import static com.google.common.base.Preconditions.checkNotNull; @@ -16,18 +15,18 @@ abstract class MethodSignature { abstract ImmutableList> parameterTypes(); abstract ImmutableList> thrownTypes(); - static MethodSignature fromExecutableElement(ExecutableElement method) { - checkNotNull(method); + static MethodSignature fromExecutableType(String methodName, ExecutableType methodType) { + checkNotNull(methodType); ImmutableList.Builder> parameters = ImmutableList.builder(); ImmutableList.Builder> thrownTypes = ImmutableList.builder(); - for (VariableElement parameter : method.getParameters()) { - parameters.add(MoreTypes.equivalence().wrap(parameter.asType())); + for (TypeMirror parameter : methodType.getParameterTypes()) { + parameters.add(MoreTypes.equivalence().wrap(parameter)); } - for (TypeMirror thrownType : method.getThrownTypes()) { + for (TypeMirror thrownType : methodType.getThrownTypes()) { thrownTypes.add(MoreTypes.equivalence().wrap(thrownType)); } return new AutoValue_MethodSignature( - method.getSimpleName().toString(), + methodName, parameters.build(), thrownTypes.build()); } From a004d3e20fb8e3203fad9861e67a287ea6d694eb Mon Sep 17 00:00:00 2001 From: cgruber Date: Mon, 6 Apr 2015 11:07:02 -0700 Subject: [PATCH 11/16] Mark Dagger 2 experimental APIs as experimental. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90429548 --- core/src/main/java/dagger/MapKey.java | 2 ++ core/src/main/java/dagger/Provides.java | 2 ++ core/src/main/java/dagger/internal/Beta.java | 33 +++++++++++++++++++ .../main/java/dagger/producers/Produced.java | 2 ++ .../main/java/dagger/producers/Producer.java | 2 ++ .../java/dagger/producers/ProducerModule.java | 5 ++- .../main/java/dagger/producers/Produces.java | 5 ++- .../dagger/producers/ProductionComponent.java | 7 ++-- 8 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/dagger/internal/Beta.java diff --git a/core/src/main/java/dagger/MapKey.java b/core/src/main/java/dagger/MapKey.java index c6bf6d70a79..8699c42a006 100644 --- a/core/src/main/java/dagger/MapKey.java +++ b/core/src/main/java/dagger/MapKey.java @@ -15,6 +15,7 @@ */ package dagger; +import dagger.internal.Beta; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -47,6 +48,7 @@ @Documented @Target(ANNOTATION_TYPE) @Retention(RUNTIME) +@Beta public @interface MapKey { /** * if {@code unwrapValue} is false, then the whole annotation will be the type and annotation diff --git a/core/src/main/java/dagger/Provides.java b/core/src/main/java/dagger/Provides.java index df4ad904d2b..b0524b4efcf 100644 --- a/core/src/main/java/dagger/Provides.java +++ b/core/src/main/java/dagger/Provides.java @@ -16,6 +16,7 @@ */ package dagger; +import dagger.internal.Beta; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -61,6 +62,7 @@ enum Type { * is contributed to the map as a key/value pair. The {@code Map>} produced from * the accumulation of values will be immutable. */ + @Beta MAP; } 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 00000000000..a0a82c65922 --- /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/producers/src/main/java/dagger/producers/Produced.java b/producers/src/main/java/dagger/producers/Produced.java index 137244bad9b..9019aa657bd 100644 --- a/producers/src/main/java/dagger/producers/Produced.java +++ b/producers/src/main/java/dagger/producers/Produced.java @@ -15,6 +15,7 @@ */ package dagger.producers; +import dagger.internal.Beta; import java.util.concurrent.ExecutionException; /** @@ -36,6 +37,7 @@ * * @author Jesse Beder */ +@Beta public interface Produced { /** * Returns the result of a production. diff --git a/producers/src/main/java/dagger/producers/Producer.java b/producers/src/main/java/dagger/producers/Producer.java index fdf7dddcf00..5aeb4a03da2 100644 --- a/producers/src/main/java/dagger/producers/Producer.java +++ b/producers/src/main/java/dagger/producers/Producer.java @@ -15,6 +15,7 @@ */ package dagger.producers; +import dagger.internal.Beta; import com.google.common.util.concurrent.ListenableFuture; /** @@ -86,6 +87,7 @@ * * @author Jesse Beder */ +@Beta public interface Producer { /** * Returns a future representing a running task that produces a value. Calling this method will diff --git a/producers/src/main/java/dagger/producers/ProducerModule.java b/producers/src/main/java/dagger/producers/ProducerModule.java index f86cf12a3e5..714e3fa3e47 100644 --- a/producers/src/main/java/dagger/producers/ProducerModule.java +++ b/producers/src/main/java/dagger/producers/ProducerModule.java @@ -16,6 +16,7 @@ package dagger.producers; import dagger.Module; +import dagger.internal.Beta; import java.lang.annotation.Documented; import java.lang.annotation.Target; @@ -26,7 +27,9 @@ * * @author Jesse Beder */ -@Documented @Target(TYPE) +@Documented +@Target(TYPE) +@Beta public @interface ProducerModule { /** * Additional {@code @ProducerModule}- or {@link Module}-annotated classes from which this module diff --git a/producers/src/main/java/dagger/producers/Produces.java b/producers/src/main/java/dagger/producers/Produces.java index 6f77c3c2d97..1b57bc39df7 100644 --- a/producers/src/main/java/dagger/producers/Produces.java +++ b/producers/src/main/java/dagger/producers/Produces.java @@ -15,6 +15,7 @@ */ package dagger.producers; +import dagger.internal.Beta; import com.google.common.util.concurrent.ListenableFuture; import java.lang.annotation.Documented; import java.lang.annotation.Target; @@ -29,7 +30,9 @@ * * @author Jesse Beder */ -@Documented @Target(METHOD) +@Documented +@Target(METHOD) +@Beta public @interface Produces { /** The type of binding into which the return type of the annotated method contributes. */ enum Type { diff --git a/producers/src/main/java/dagger/producers/ProductionComponent.java b/producers/src/main/java/dagger/producers/ProductionComponent.java index 02ba7c879db..e4fe125baa2 100644 --- a/producers/src/main/java/dagger/producers/ProductionComponent.java +++ b/producers/src/main/java/dagger/producers/ProductionComponent.java @@ -18,6 +18,7 @@ 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; @@ -61,11 +62,13 @@ *

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(user): Explain this more thoroughly, and possibly update the javadocs of those utilities. + * * * @author Jesse Beder */ -@Documented @Target(TYPE) +@Documented +@Target(TYPE) +@Beta public @interface ProductionComponent { /** * A list of classes annotated with {@link Module} or {@link ProducerModule} whose bindings are From 70f720bc4a25cadfb833194d6c5822fb3c39c6bd Mon Sep 17 00:00:00 2001 From: cgruber Date: Mon, 6 Apr 2015 11:44:57 -0700 Subject: [PATCH 12/16] Remove Dagger 1.x compatible annotation members from the Module in the open-source project. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90433194 --- core/src/main/java/dagger/Module.java | 64 +-------------------------- 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/core/src/main/java/dagger/Module.java b/core/src/main/java/dagger/Module.java index d566c587630..05f0f3a6a6f 100644 --- a/core/src/main/java/dagger/Module.java +++ b/core/src/main/java/dagger/Module.java @@ -26,73 +26,11 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Module { - /** - * Returns classes that object graphs created with this module must be able to - * inject. This includes both classes passed to {@link ObjectGraph#get} and - * the types of instances passed {@link ObjectGraph#inject}. - * - *

It is an error to call {@link ObjectGraph#get} or {@link - * ObjectGraph#inject} with a type that isn't listed in the {@code injects} - * set for any of the object graph's modules. Making such a call will trigger - * an {@code IllegalArgumentException} at runtime. - * - *

Maintaining this set is onerous, but doing so provides benefits to the - * application. This set enables dagger to perform more aggressive static - * analysis than would be otherwise possible: - *

    - *
  • Detect missing bindings. Dagger can check that all - * injected dependencies can be satisfied. Set {@code complete=false} to - * disable this check for the current module. - *
  • Detect unused bindings. Dagger can check that all - * provides methods are used to satisfy injected dependencies. Set - * {@code library=true} to disable this check for the current module. - *
- */ - Class[] injects() default { }; - Class[] staticInjections() default { }; - - /** - * True if {@code @Provides} methods from this module are permitted to - * override those of other modules. This is a dangerous feature as it permits - * binding conflicts to go unnoticed. It should only be used in test and - * development modules. - */ - boolean overrides() default false; - /** * 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 { }; - - /** - * An optional {@code @Module}-annotated class upon which this module can be - * {@link ObjectGraph#plus added} to form a complete graph. - */ - Class addsTo() default Void.class; - - /** - * True if all of the bindings required by this module can also be satisfied - * by this module, its {@link #includes} and its {@link #addsTo}. If a module - * is complete it is eligible for additional static checking: tools can detect - * if required bindings are not available. Modules that have external - * dependencies must use {@code complete = false}. - */ - boolean complete() default true; - - /** - * False if all the included bindings in this module are necessary to satisfy - * all of its {@link #injects injectable types}. If a module is not a library - * module, it is eligible for additional static checking: tools can detect if - * included bindings are not necessary. If you provide bindings that are not - * used by this module's graph, then you must declare {@code library = true}. - * - *

This is intended to help you detect dead code. As of 2.0 Dagger ignores - * this property and it is present for compatibility with Dagger 1.x during - * migrations. - */ - // TODO(cgruber): Deprecate this property. - boolean library() default true; + Class[] includes() default {}; } From 92b86bf35c56f82389d821e71c664fe07994f7a0 Mon Sep 17 00:00:00 2001 From: gak Date: Mon, 6 Apr 2015 15:40:05 -0700 Subject: [PATCH 13/16] Add a substantial amount of content to the @Component javadoc. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90455224 --- core/src/main/java/dagger/Component.java | 172 ++++++++++++++++++-- core/src/main/java/dagger/Subcomponent.java | 15 +- 2 files changed, 165 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/dagger/Component.java b/core/src/main/java/dagger/Component.java index 637f60203cb..69903b5b92a 100644 --- a/core/src/main/java/dagger/Component.java +++ b/core/src/main/java/dagger/Component.java @@ -21,6 +21,7 @@ import javax.inject.Inject; import javax.inject.Provider; import javax.inject.Qualifier; +import javax.inject.Scope; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -28,47 +29,192 @@ /** * 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}. + * 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}. * + * *

Component methods

+ * * *

Every type annotated with {@code @Component} must contain at least one abstract component - * method. Component methods must either represent {@linkplain Provider provision} or - * {@linkplain MembersInjector member injection}. + * method. Component methods may have any name, but must have signatures that conform to either + * {@linkplain Provider provision} or {@linkplain MembersInjector members-injection} contracts. * - * Provision methods have no arguments and return an {@link Inject injected} or - * {@link Provides provided} type. Each may have a {@link Qualifier} annotation as well. The + * + *

Provision methods

+ * + * + *

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:


  *   SomeType getSomeType();
  *   {@literal Set} getSomeTypes();
  *   {@literal @PortNumber} int getPortNumber();
  * 
* - * Member injection methods take a single parameter and optionally return that same type. The - * following are all valid member injection method declarations:

+ * 

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:


+ *   SomeType getSomeType();
+ *   {@literal Provider} getSomeTypeProvider();
+ *   {@literal Lazy} getLazySomeType();
+ * 
+ * + * + *

Members-injection methods

+ *
+ * + *

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:


  *   void injectSomeType(SomeType someType);
  *   SomeType injectAndReturnSomeType(SomeType someType);
  * 
* + *

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:


+ *   {@literal MembersInjector} getSomeTypeMembersInjector();
+ * 
+ * + *

A note about covariance

+ * + *

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)}:


+ *   class Parent {
+ *     @Inject A a;
+ *   }
+ *
+ *   class Self extends Parent {
+ *     @Inject B b;
+ *   }
+ *
+ *   class Child extends Self {
+ *     @Inject C c;
+ *   }
+ * 
+ * + * + *

Instantiation

+ *
+ * + *

Component implementations are primarily instantiated via a generated + * builder. An instance of the builder + * is obtained using the {@code builder()} method on the component implementation. The returned + * builder has a method to set each of the {@linkplain #modules} and component + * {@linkplain #dependencies} named with the lower + * camel case 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:


+ *   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();
+ *   }
+ * 
+ * + *

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. + * + * + *

Scope

+ * + * + *

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:


+ *   @Singleton @Component
+ *   interface MyApplicationComponent {
+ *     // this component can only inject types using unscoped or @Singleton bindings
+ *   }
+ * 
+ * + *

In order to get the proper behavior associated with a scope annotation, it is the caller's + * responsibility to instaniate 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. + * + * + *

Component relationships

+ * + * + *

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. + * + * + *

Subcomponents

+ * + * + *

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 entire 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. + * + *

Subcomponents are delared 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 subcomponents's modules, but must at least include those without visible + * no-arg constructors. The follwing is an example of a factory method that creates a request-scoped + * subcomponent from a singleton-scoped parent:


+ *   @Singleton @Component
+ *   interface ApplicationComponent {
+ *     // component methods...
+ *
+ *     RequestComponent newRequestComponent(RequestModule requestModule);
+ *   }
+ * 
+ * + * + *

Component dependencies

+ *
+ * + *

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 + * component interface by declaring a {@linkplain #dependencies component dependency}. When + * a type is used as a component dependency, each provision method + * on the dependency is bound as a provider. Note that only the bindings exposed as + * provision methods are available through component dependencies. + * * @author Gregory Kick * @since 2.0 */ -// TODO(gak): add missing spec for @Scope -// TODO(gak): add missing spec for component dependencies @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. + * 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 component dependencies. + * A list of types that are to be used as component + * dependencies. */ Class[] dependencies() default {}; } diff --git a/core/src/main/java/dagger/Subcomponent.java b/core/src/main/java/dagger/Subcomponent.java index 1775050c554..1c8799515dc 100644 --- a/core/src/main/java/dagger/Subcomponent.java +++ b/core/src/main/java/dagger/Subcomponent.java @@ -21,24 +21,21 @@ import static java.lang.annotation.ElementType.TYPE; /** - * A component that inherits the bindings from a parent {@link Component} or {@link Subcomponent}. - * - *

Subcomponent implementations only exist in the context of a parent and are associated with - * parents using factory methods on the component. Simply add a method that returns the - * subcomponent on the parent. + * 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 */ -// TODO(gak): add missing spec for @Scope, validation, etc. @Target(TYPE) @Documented public @interface Subcomponent { /** * A list of classes annotated with {@link Module} whose bindings are used to generate the - * component implementation. - * - *

At the moment, only modules without arguments are supported. + * 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 {}; } From fa669f144e6191513449ac6deebdc963b6167d59 Mon Sep 17 00:00:00 2001 From: cgruber Date: Tue, 7 Apr 2015 09:24:13 -0700 Subject: [PATCH 14/16] Remove now-obsolete annotation members from tests. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90516262 --- .../internal/codegen/DependencyRequestMapperTest.java | 2 +- .../src/test/java/dagger/internal/codegen/KeyTest.java | 10 +++++----- examples/simple/src/main/java/coffee/PumpModule.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java index 0232d1c3856..76b28e461a6 100644 --- a/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/DependencyRequestMapperTest.java @@ -128,7 +128,7 @@ private DependencyRequest dependencyRequestForProduced() { .isEqualTo(Producer.class); } - @Module(library = true) + @Module static final class ProvidesMethodModule { @Provides String provideString( Integer a, Lazy b, Provider c, MembersInjector d) { diff --git a/compiler/src/test/java/dagger/internal/codegen/KeyTest.java b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java index dde52f75465..c1d622dfde0 100644 --- a/compiler/src/test/java/dagger/internal/codegen/KeyTest.java +++ b/compiler/src/test/java/dagger/internal/codegen/KeyTest.java @@ -94,7 +94,7 @@ static final class InjectedClass { MoreTypes.equivalence().wrap(stringType))); } - @Module(library = true) + @Module static final class ProvidesMethodModule { @Provides String provideString() { return null; @@ -135,7 +135,7 @@ static final class ProvidesMethodModule { assertThat(provisionKey).isEqualTo(injectionKey); } - @Module(library = true) + @Module static final class QualifiedProvidesMethodModule { @Provides @TestQualifier(@InnerAnnotation) @@ -171,7 +171,7 @@ static final class QualifiedFieldHolder { } } - @Module(library = true) + @Module static final class SetProvidesMethodsModule { @Provides(type = SET) String provideString() { return null; @@ -182,14 +182,14 @@ static final class SetProvidesMethodsModule { } } - @Module(library = true) + @Module static final class PrimitiveTypes { @Provides int foo() { return 0; } } - @Module(library = true) + @Module static final class BoxedPrimitiveTypes { @Provides Integer foo() { return 0; diff --git a/examples/simple/src/main/java/coffee/PumpModule.java b/examples/simple/src/main/java/coffee/PumpModule.java index b064cea658f..338ad33c234 100644 --- a/examples/simple/src/main/java/coffee/PumpModule.java +++ b/examples/simple/src/main/java/coffee/PumpModule.java @@ -3,7 +3,7 @@ import dagger.Module; import dagger.Provides; -@Module(complete = false, library = true) +@Module class PumpModule { @Provides Pump providePump(Thermosiphon pump) { return pump; From 19b85c9334749bf7b2a7c09d68037fe171ee61d2 Mon Sep 17 00:00:00 2001 From: cgruber Date: Tue, 7 Apr 2015 10:41:17 -0700 Subject: [PATCH 15/16] Remove the default groupId to simplify the poms. Also bump auto-service to rc2. Note: This altered the xml formatting, which will be fixed in a later commit ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90524096 --- compiler/pom.xml | 45 +++++++++++++++++++++------------------------ pom.xml | 5 +---- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/compiler/pom.xml b/compiler/pom.xml index 03b96b106b2..5ac25dd7dcd 100644 --- a/compiler/pom.xml +++ b/compiler/pom.xml @@ -105,32 +105,30 @@ - org.apache.maven.plugins maven-compiler-plugin - - - default-compile - compile - - - com.google.auto.value.processor.AutoValueProcessor - com.google.auto.service.processor.AutoServiceProcessor - - - - - default-test-compile - testCompile - - - dagger.internal.codegen.ComponentProcessor - - - - + + + default-compile + compile + + + com.google.auto.value.processor.AutoValueProcessor + com.google.auto.service.processor.AutoServiceProcessor + + + + + default-test-compile + testCompile + + + dagger.internal.codegen.ComponentProcessor + + + + - org.apache.maven.plugins maven-invoker-plugin true @@ -157,7 +155,6 @@ - org.apache.maven.plugins maven-shade-plugin 2.3 diff --git a/pom.xml b/pom.xml index df36e3670cf..e0084798783 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 1 2.5.0 1.0-SNAPSHOT - 1.0-rc1 + 1.0-rc2 1.0 18.0 @@ -161,7 +161,6 @@ - org.apache.maven.plugins maven-compiler-plugin ${java.version} @@ -173,7 +172,6 @@ - org.apache.maven.plugins maven-release-plugin 2.3.2 @@ -189,7 +187,6 @@ - org.apache.maven.plugins maven-checkstyle-plugin 2.10 From f03415a082e73e0f74fd9152cf33066dc420bce0 Mon Sep 17 00:00:00 2001 From: cgruber Date: Tue, 7 Apr 2015 10:56:15 -0700 Subject: [PATCH 16/16] Move off of a google-internal API on FluentIterable. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=90525706 --- .../dagger/internal/codegen/BindingGraphValidator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java index e886353edc6..47d51015f8a 100644 --- a/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java +++ b/compiler/src/main/java/dagger/internal/codegen/BindingGraphValidator.java @@ -745,8 +745,11 @@ private String formatBindingType(BindingType type) { private void reportCycle(DependencyRequest request, Deque path, final ValidationReport.Builder reportBuilder) { - ImmutableList printableDependencyPath = FluentIterable.of(request) - .append(Iterables.transform(path, REQUEST_FROM_RESOLVED_REQUEST)) + ImmutableList pathElements = ImmutableList.builder() + .add(request) + .addAll(Iterables.transform(path, REQUEST_FROM_RESOLVED_REQUEST)) + .build(); + ImmutableList printableDependencyPath = FluentIterable.from(pathElements) .transform(dependencyRequestFormatter) .filter(Predicates.not(Predicates.equalTo(""))) .toList()