| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Dagger Authors. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package dagger.internal.codegen; |
| 18 | |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 19 | import static com.google.common.base.Preconditions.checkNotNull; |
| 20 | import static com.squareup.javapoet.MethodSpec.methodBuilder; |
| 21 | import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom; |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 22 | import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.MEMBERS_INJECTION_METHOD; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 23 | import static dagger.internal.codegen.Util.reentrantComputeIfAbsent; |
| 24 | import static javax.lang.model.element.Modifier.PRIVATE; |
| 25 | |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 26 | import com.google.common.collect.ImmutableSet; |
| 27 | import com.squareup.javapoet.ClassName; |
| 28 | import com.squareup.javapoet.CodeBlock; |
| 29 | import com.squareup.javapoet.MethodSpec; |
| 30 | import com.squareup.javapoet.ParameterSpec; |
| 31 | import com.squareup.javapoet.TypeName; |
| 32 | import dagger.internal.codegen.InjectionMethods.InjectionSiteMethod; |
| 33 | import dagger.internal.codegen.MembersInjectionBinding.InjectionSite; |
| ronshapiro | a6f99ed | 2017-12-12 09:26:26 -0800 | [diff] [blame] | 34 | import dagger.model.Key; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 35 | import java.util.LinkedHashMap; |
| 36 | import java.util.Map; |
| 37 | import javax.lang.model.element.Name; |
| 38 | import javax.lang.model.element.TypeElement; |
| 39 | import javax.lang.model.type.TypeMirror; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 40 | |
| 41 | /** Manages the member injection methods for a component. */ |
| 42 | final class MembersInjectionMethods { |
| 43 | private final Map<Key, MethodSpec> membersInjectionMethods = new LinkedHashMap<>(); |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 44 | private final ComponentImplementation componentImplementation; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 45 | private final ComponentBindingExpressions bindingExpressions; |
| 46 | private final BindingGraph graph; |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 47 | private final DaggerElements elements; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 48 | private final DaggerTypes types; |
| 49 | |
| 50 | MembersInjectionMethods( |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 51 | ComponentImplementation componentImplementation, |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 52 | ComponentBindingExpressions bindingExpressions, |
| 53 | BindingGraph graph, |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 54 | DaggerElements elements, |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 55 | DaggerTypes types) { |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 56 | this.componentImplementation = checkNotNull(componentImplementation); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 57 | this.bindingExpressions = checkNotNull(bindingExpressions); |
| 58 | this.graph = checkNotNull(graph); |
| 59 | this.elements = checkNotNull(elements); |
| 60 | this.types = checkNotNull(types); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if |
| 65 | * necessary. |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 66 | */ |
| 67 | MethodSpec getOrCreate(Key key) { |
| 68 | return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod); |
| 69 | } |
| 70 | |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 71 | private MethodSpec membersInjectionMethod(Key key) { |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 72 | ResolvedBindings resolvedBindings = |
| 73 | graph.membersInjectionBindings().getOrDefault(key, graph.contributionBindings().get(key)); |
| 74 | Binding binding = resolvedBindings.binding(); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 75 | TypeMirror keyType = binding.key().type(); |
| 76 | TypeMirror membersInjectedType = |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 77 | isTypeAccessibleFrom(keyType, componentImplementation.name().packageName()) |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 78 | ? keyType |
| dpb | e7b8958 | 2018-02-19 08:42:19 -0800 | [diff] [blame] | 79 | : elements.getTypeElement(Object.class).asType(); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 80 | TypeName membersInjectedTypeName = TypeName.get(membersInjectedType); |
| 81 | Name bindingTypeName = binding.bindingTypeElement().get().getSimpleName(); |
| 82 | // TODO(ronshapiro): include type parameters in this name e.g. injectFooOfT, and outer class |
| 83 | // simple names Foo.Builder -> injectFooBuilder |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 84 | String methodName = componentImplementation.getUniqueMethodName("inject" + bindingTypeName); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 85 | ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build(); |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 86 | MethodSpec.Builder methodBuilder = |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 87 | methodBuilder(methodName) |
| 88 | .addModifiers(PRIVATE) |
| 89 | .returns(membersInjectedTypeName) |
| 90 | .addParameter(parameter); |
| 91 | TypeElement canIgnoreReturnValue = |
| 92 | elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue"); |
| 93 | if (canIgnoreReturnValue != null) { |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 94 | methodBuilder.addAnnotation(ClassName.get(canIgnoreReturnValue)); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 95 | } |
| 96 | CodeBlock instance = CodeBlock.of("$N", parameter); |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 97 | methodBuilder.addCode( |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 98 | InjectionSiteMethod.invokeAll( |
| 99 | injectionSites(binding), |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 100 | componentImplementation.name(), |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 101 | instance, |
| 102 | membersInjectedType, |
| 103 | types, |
| 104 | request -> |
| 105 | bindingExpressions |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 106 | .getDependencyArgumentExpression(request, componentImplementation.name()) |
| ronshapiro | 61bdbb3 | 2018-12-21 12:01:20 -0800 | [diff] [blame] | 107 | .codeBlock(), |
| 108 | elements)); |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 109 | methodBuilder.addStatement("return $L", instance); |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 110 | |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 111 | MethodSpec method = methodBuilder.build(); |
| dpb | 159d81b | 2018-11-01 14:06:17 -0700 | [diff] [blame] | 112 | componentImplementation.addMethod(MEMBERS_INJECTION_METHOD, method); |
| bcorso | 2b8e168 | 2017-12-05 13:59:00 -0800 | [diff] [blame] | 113 | return method; |
| bcorso | c5dac09 | 2017-11-29 09:23:02 -0800 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | private static ImmutableSet<InjectionSite> injectionSites(Binding binding) { |
| 117 | if (binding instanceof ProvisionBinding) { |
| 118 | return ((ProvisionBinding) binding).injectionSites(); |
| 119 | } else if (binding instanceof MembersInjectionBinding) { |
| 120 | return ((MembersInjectionBinding) binding).injectionSites(); |
| 121 | } |
| 122 | throw new IllegalArgumentException(binding.key().toString()); |
| 123 | } |
| 124 | } |