• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.writing;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.Iterables.getOnlyElement;
21 import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
22 import static dagger.internal.codegen.javapoet.TypeNames.INSTANCE_FACTORY;
23 import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTORS;
24 
25 import androidx.room.compiler.processing.XType;
26 import androidx.room.compiler.processing.XTypeElement;
27 import com.squareup.javapoet.CodeBlock;
28 import dagger.assisted.Assisted;
29 import dagger.assisted.AssistedFactory;
30 import dagger.assisted.AssistedInject;
31 import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
32 import dagger.internal.codegen.binding.ProvisionBinding;
33 import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
34 import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
35 
36 /** A {@code Provider<MembersInjector<Foo>>} creation expression. */
37 final class MembersInjectorProviderCreationExpression
38     implements FrameworkInstanceCreationExpression {
39 
40   private final ShardImplementation shardImplementation;
41   private final ComponentRequestRepresentations componentRequestRepresentations;
42   private final ProvisionBinding binding;
43 
44   @AssistedInject
MembersInjectorProviderCreationExpression( @ssisted ProvisionBinding binding, ComponentImplementation componentImplementation, ComponentRequestRepresentations componentRequestRepresentations)45   MembersInjectorProviderCreationExpression(
46       @Assisted ProvisionBinding binding,
47       ComponentImplementation componentImplementation,
48       ComponentRequestRepresentations componentRequestRepresentations) {
49     this.binding = checkNotNull(binding);
50     this.shardImplementation = componentImplementation.shardImplementation(binding);
51     this.componentRequestRepresentations = checkNotNull(componentRequestRepresentations);
52   }
53 
54   @Override
creationExpression()55   public CodeBlock creationExpression() {
56     XType membersInjectedType =
57         getOnlyElement(binding.key().type().xprocessing().getTypeArguments());
58 
59     boolean castThroughRawType = false;
60     CodeBlock membersInjector;
61     if (binding.injectionSites().isEmpty()) {
62       membersInjector =
63           CodeBlock.of("$T.<$T>noOp()", MEMBERS_INJECTORS, membersInjectedType.getTypeName());
64     } else {
65       XTypeElement injectedTypeElement = membersInjectedType.getTypeElement();
66       while (!hasLocalInjectionSites(injectedTypeElement)) {
67         // Cast through a raw type since we're going to be using the MembersInjector for the
68         // parent type.
69         castThroughRawType = true;
70         injectedTypeElement = injectedTypeElement.getSuperType().getTypeElement();
71       }
72 
73       membersInjector =
74           CodeBlock.of(
75               "$T.create($L)",
76               membersInjectorNameForType(injectedTypeElement),
77               componentRequestRepresentations.getCreateMethodArgumentsCodeBlock(
78                   binding, shardImplementation.name()));
79     }
80 
81     // TODO(ronshapiro): consider adding a MembersInjectorRequestRepresentation to return this
82     // directly
83     // (as it's rarely requested as a Provider).
84     CodeBlock providerExpression = CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
85     // If needed we cast through raw type around the InstanceFactory type as opposed to the
86     // MembersInjector since we end up with an InstanceFactory<MembersInjector> as opposed to a
87     // InstanceFactory<MembersInjector<Foo>> and that becomes unassignable. To fix it would require
88     // a second cast. If we just cast to the raw type InstanceFactory though, that becomes
89     // assignable.
90     return castThroughRawType
91         ? CodeBlock.of("($T) $L", INSTANCE_FACTORY, providerExpression)
92         : providerExpression;
93   }
94 
hasLocalInjectionSites(XTypeElement injectedTypeElement)95   private boolean hasLocalInjectionSites(XTypeElement injectedTypeElement) {
96     return binding.injectionSites().stream()
97         .map(InjectionSite::enclosingTypeElement)
98         .anyMatch(injectedTypeElement::equals);
99   }
100 
101   @AssistedFactory
102   static interface Factory {
create(ProvisionBinding binding)103     MembersInjectorProviderCreationExpression create(ProvisionBinding binding);
104   }
105 }
106