• 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;
18 
19 import static com.google.auto.common.MoreElements.getPackage;
20 import static com.google.auto.common.MoreElements.isAnnotationPresent;
21 import static com.google.common.base.CaseFormat.LOWER_CAMEL;
22 import static com.google.common.base.CaseFormat.UPPER_CAMEL;
23 import static com.google.common.base.Verify.verify;
24 import static com.google.common.collect.Iterables.transform;
25 import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
26 import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
27 import static dagger.internal.codegen.SourceFiles.classFileName;
28 import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
29 import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
30 import static javax.lang.model.type.TypeKind.DECLARED;
31 import static javax.lang.model.type.TypeKind.NONE;
32 import static javax.lang.model.util.ElementFilter.methodsIn;
33 
34 import com.google.auto.common.MoreElements;
35 import com.google.auto.common.MoreTypes;
36 import com.google.auto.value.AutoValue;
37 import com.google.auto.value.extension.memoized.Memoized;
38 import com.google.common.collect.ImmutableSet;
39 import com.google.common.graph.Traverser;
40 import com.google.errorprone.annotations.CanIgnoreReturnValue;
41 import com.squareup.javapoet.ClassName;
42 import dagger.Binds;
43 import dagger.BindsOptionalOf;
44 import dagger.Module;
45 import dagger.Provides;
46 import dagger.internal.codegen.langmodel.DaggerElements;
47 import dagger.model.Key;
48 import dagger.multibindings.Multibinds;
49 import dagger.producers.Produces;
50 import java.util.HashMap;
51 import java.util.LinkedHashSet;
52 import java.util.Map;
53 import java.util.Set;
54 import javax.inject.Inject;
55 import javax.inject.Singleton;
56 import javax.lang.model.element.ExecutableElement;
57 import javax.lang.model.element.TypeElement;
58 import javax.lang.model.type.TypeMirror;
59 
60 @AutoValue
61 abstract class ModuleDescriptor {
62 
moduleElement()63   abstract TypeElement moduleElement();
64 
includedModules()65   abstract ImmutableSet<TypeElement> includedModules();
66 
bindings()67   abstract ImmutableSet<ContributionBinding> bindings();
68 
69   /** The multibinding declarations contained in this module. */
multibindingDeclarations()70   abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
71 
72   /** The {@link Module#subcomponents() subcomponent declarations} contained in this module. */
subcomponentDeclarations()73   abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
74 
75   /** The {@link Binds} method declarations that define delegate bindings. */
delegateDeclarations()76   abstract ImmutableSet<DelegateDeclaration> delegateDeclarations();
77 
78   /** The {@link BindsOptionalOf} method declarations that define optional bindings. */
optionalDeclarations()79   abstract ImmutableSet<OptionalBindingDeclaration> optionalDeclarations();
80 
81   /** The kind of the module. */
kind()82   abstract ModuleKind kind();
83 
84   /** Returns all of the bindings declared in this module. */
85   @Memoized
allBindingDeclarations()86   ImmutableSet<BindingDeclaration> allBindingDeclarations() {
87     return ImmutableSet.<BindingDeclaration>builder()
88         .addAll(bindings())
89         .addAll(delegateDeclarations())
90         .addAll(multibindingDeclarations())
91         .addAll(optionalDeclarations())
92         .addAll(subcomponentDeclarations())
93         .build();
94   }
95 
96   /** Returns the keys of all bindings declared by this module. */
allBindingKeys()97   ImmutableSet<Key> allBindingKeys() {
98     return allBindingDeclarations().stream().map(BindingDeclaration::key).collect(toImmutableSet());
99   }
100 
101   @Singleton
102   static final class Factory implements ClearableCache {
103     private final DaggerElements elements;
104     private final BindingFactory bindingFactory;
105     private final MultibindingDeclaration.Factory multibindingDeclarationFactory;
106     private final DelegateDeclaration.Factory bindingDelegateDeclarationFactory;
107     private final SubcomponentDeclaration.Factory subcomponentDeclarationFactory;
108     private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory;
109     private final Map<TypeElement, ModuleDescriptor> cache = new HashMap<>();
110 
111     @Inject
Factory( DaggerElements elements, BindingFactory bindingFactory, MultibindingDeclaration.Factory multibindingDeclarationFactory, DelegateDeclaration.Factory bindingDelegateDeclarationFactory, SubcomponentDeclaration.Factory subcomponentDeclarationFactory, OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory)112     Factory(
113         DaggerElements elements,
114         BindingFactory bindingFactory,
115         MultibindingDeclaration.Factory multibindingDeclarationFactory,
116         DelegateDeclaration.Factory bindingDelegateDeclarationFactory,
117         SubcomponentDeclaration.Factory subcomponentDeclarationFactory,
118         OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory) {
119       this.elements = elements;
120       this.bindingFactory = bindingFactory;
121       this.multibindingDeclarationFactory = multibindingDeclarationFactory;
122       this.bindingDelegateDeclarationFactory = bindingDelegateDeclarationFactory;
123       this.subcomponentDeclarationFactory = subcomponentDeclarationFactory;
124       this.optionalBindingDeclarationFactory = optionalBindingDeclarationFactory;
125     }
126 
create(TypeElement moduleElement)127     ModuleDescriptor create(TypeElement moduleElement) {
128       return reentrantComputeIfAbsent(cache, moduleElement, this::createUncached);
129     }
130 
createUncached(TypeElement moduleElement)131     ModuleDescriptor createUncached(TypeElement moduleElement) {
132       ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
133       ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder();
134       ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations =
135           ImmutableSet.builder();
136       ImmutableSet.Builder<OptionalBindingDeclaration> optionalDeclarations =
137           ImmutableSet.builder();
138 
139       for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
140         if (isAnnotationPresent(moduleMethod, Provides.class)) {
141           bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement));
142         }
143         if (isAnnotationPresent(moduleMethod, Produces.class)) {
144           bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement));
145         }
146         if (isAnnotationPresent(moduleMethod, Binds.class)) {
147           delegates.add(bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement));
148         }
149         if (isAnnotationPresent(moduleMethod, Multibinds.class)) {
150           multibindingDeclarations.add(
151               multibindingDeclarationFactory.forMultibindsMethod(moduleMethod, moduleElement));
152         }
153         if (isAnnotationPresent(moduleMethod, BindsOptionalOf.class)) {
154           optionalDeclarations.add(
155               optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement));
156         }
157       }
158 
159       return new AutoValue_ModuleDescriptor(
160           moduleElement,
161           ImmutableSet.copyOf(collectIncludedModules(new LinkedHashSet<>(), moduleElement)),
162           bindings.build(),
163           multibindingDeclarations.build(),
164           subcomponentDeclarationFactory.forModule(moduleElement),
165           delegates.build(),
166           optionalDeclarations.build(),
167           ModuleKind.forAnnotatedElement(moduleElement).get());
168     }
169 
170     /** Returns all the modules transitively included by given modules, including the arguments. */
transitiveModules(Iterable<TypeElement> modules)171     ImmutableSet<ModuleDescriptor> transitiveModules(Iterable<TypeElement> modules) {
172       return ImmutableSet.copyOf(
173           Traverser.forGraph(
174                   (ModuleDescriptor module) -> transform(module.includedModules(), this::create))
175               .depthFirstPreOrder(transform(modules, this::create)));
176     }
177 
178     @CanIgnoreReturnValue
collectIncludedModules( Set<TypeElement> includedModules, TypeElement moduleElement)179     private Set<TypeElement> collectIncludedModules(
180         Set<TypeElement> includedModules, TypeElement moduleElement) {
181       TypeMirror superclass = moduleElement.getSuperclass();
182       if (!superclass.getKind().equals(NONE)) {
183         verify(superclass.getKind().equals(DECLARED));
184         TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
185         if (!superclassElement.getQualifiedName().contentEquals(Object.class.getCanonicalName())) {
186           collectIncludedModules(includedModules, superclassElement);
187         }
188       }
189       moduleAnnotation(moduleElement)
190           .ifPresent(
191               moduleAnnotation -> {
192                 includedModules.addAll(moduleAnnotation.includes());
193                 includedModules.addAll(implicitlyIncludedModules(moduleElement));
194               });
195       return includedModules;
196     }
197 
198     // @ContributesAndroidInjector generates a module that is implicitly included in the enclosing
199     // module
implicitlyIncludedModules(TypeElement moduleElement)200     private ImmutableSet<TypeElement> implicitlyIncludedModules(TypeElement moduleElement) {
201       TypeElement contributesAndroidInjector =
202           elements.getTypeElement("dagger.android.ContributesAndroidInjector");
203       if (contributesAndroidInjector == null) {
204         return ImmutableSet.of();
205       }
206       return methodsIn(moduleElement.getEnclosedElements()).stream()
207           .filter(method -> isAnnotationPresent(method, contributesAndroidInjector.asType()))
208           .map(method -> elements.checkTypePresent(implicitlyIncludedModuleName(method)))
209           .collect(toImmutableSet());
210     }
211 
implicitlyIncludedModuleName(ExecutableElement method)212     private String implicitlyIncludedModuleName(ExecutableElement method) {
213       return getPackage(method).getQualifiedName()
214           + "."
215           + classFileName(ClassName.get(MoreElements.asType(method.getEnclosingElement())))
216           + "_"
217           + LOWER_CAMEL.to(UPPER_CAMEL, method.getSimpleName().toString());
218     }
219 
220     @Override
clearCache()221     public void clearCache() {
222       cache.clear();
223     }
224   }
225 }
226