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.binding; 18 19 import static androidx.room.compiler.processing.compat.XConverters.toJavac; 20 import static androidx.room.compiler.processing.compat.XConverters.toXProcessing; 21 import static com.google.auto.common.MoreElements.asExecutable; 22 import static com.google.common.base.CaseFormat.LOWER_CAMEL; 23 import static com.google.common.base.CaseFormat.UPPER_CAMEL; 24 import static com.google.common.base.Verify.verify; 25 import static com.google.common.collect.Collections2.transform; 26 import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation; 27 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent; 28 import static dagger.internal.codegen.binding.SourceFiles.classFileName; 29 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; 30 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 31 import static dagger.internal.codegen.langmodel.DaggerElements.getMethodDescriptor; 32 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; 33 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 34 import static javax.lang.model.util.ElementFilter.methodsIn; 35 36 import androidx.room.compiler.processing.XElementKt; 37 import androidx.room.compiler.processing.XMethodElement; 38 import androidx.room.compiler.processing.XProcessingEnv; 39 import androidx.room.compiler.processing.XType; 40 import androidx.room.compiler.processing.XTypeElement; 41 import com.google.auto.value.AutoValue; 42 import com.google.auto.value.extension.memoized.Memoized; 43 import com.google.common.collect.ImmutableSet; 44 import com.google.common.graph.Traverser; 45 import com.squareup.javapoet.ClassName; 46 import com.squareup.javapoet.TypeName; 47 import dagger.Binds; 48 import dagger.BindsOptionalOf; 49 import dagger.Module; 50 import dagger.internal.codegen.base.ClearableCache; 51 import dagger.internal.codegen.base.DaggerSuperficialValidation; 52 import dagger.internal.codegen.base.ModuleKind; 53 import dagger.internal.codegen.javapoet.TypeNames; 54 import dagger.internal.codegen.langmodel.DaggerElements; 55 import dagger.internal.codegen.xprocessing.XElements; 56 import dagger.spi.model.Key; 57 import java.util.Collection; 58 import java.util.HashMap; 59 import java.util.LinkedHashSet; 60 import java.util.Map; 61 import java.util.Set; 62 import javax.inject.Inject; 63 import javax.inject.Singleton; 64 65 /** Contains metadata that describes a module. */ 66 @AutoValue 67 public abstract class ModuleDescriptor { 68 moduleElement()69 public abstract XTypeElement moduleElement(); 70 bindings()71 public abstract ImmutableSet<ContributionBinding> bindings(); 72 73 /** The multibinding declarations contained in this module. */ multibindingDeclarations()74 abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations(); 75 76 /** The {@link Module#subcomponents() subcomponent declarations} contained in this module. */ subcomponentDeclarations()77 abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations(); 78 79 /** The {@link Binds} method declarations that define delegate bindings. */ delegateDeclarations()80 abstract ImmutableSet<DelegateDeclaration> delegateDeclarations(); 81 82 /** The {@link BindsOptionalOf} method declarations that define optional bindings. */ optionalDeclarations()83 abstract ImmutableSet<OptionalBindingDeclaration> optionalDeclarations(); 84 85 /** The kind of the module. */ kind()86 public abstract ModuleKind kind(); 87 88 /** Returns all of the bindings declared in this module. */ 89 @Memoized allBindingDeclarations()90 public ImmutableSet<BindingDeclaration> allBindingDeclarations() { 91 return ImmutableSet.<BindingDeclaration>builder() 92 .addAll(bindings()) 93 .addAll(delegateDeclarations()) 94 .addAll(multibindingDeclarations()) 95 .addAll(optionalDeclarations()) 96 .addAll(subcomponentDeclarations()) 97 .build(); 98 } 99 100 /** Returns the keys of all bindings declared by this module. */ allBindingKeys()101 ImmutableSet<Key> allBindingKeys() { 102 return allBindingDeclarations().stream().map(BindingDeclaration::key).collect(toImmutableSet()); 103 } 104 105 /** A {@link ModuleDescriptor} factory. */ 106 @Singleton 107 public static final class Factory implements ClearableCache { 108 private final XProcessingEnv processingEnv; 109 private final DaggerElements elements; 110 private final BindingFactory bindingFactory; 111 private final MultibindingDeclaration.Factory multibindingDeclarationFactory; 112 private final DelegateDeclaration.Factory bindingDelegateDeclarationFactory; 113 private final SubcomponentDeclaration.Factory subcomponentDeclarationFactory; 114 private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory; 115 private final DaggerSuperficialValidation superficialValidation; 116 private final Map<XTypeElement, ModuleDescriptor> cache = new HashMap<>(); 117 118 @Inject Factory( XProcessingEnv processingEnv, DaggerElements elements, BindingFactory bindingFactory, MultibindingDeclaration.Factory multibindingDeclarationFactory, DelegateDeclaration.Factory bindingDelegateDeclarationFactory, SubcomponentDeclaration.Factory subcomponentDeclarationFactory, OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory, DaggerSuperficialValidation superficialValidation)119 Factory( 120 XProcessingEnv processingEnv, 121 DaggerElements elements, 122 BindingFactory bindingFactory, 123 MultibindingDeclaration.Factory multibindingDeclarationFactory, 124 DelegateDeclaration.Factory bindingDelegateDeclarationFactory, 125 SubcomponentDeclaration.Factory subcomponentDeclarationFactory, 126 OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory, 127 DaggerSuperficialValidation superficialValidation) { 128 this.processingEnv = processingEnv; 129 this.elements = elements; 130 this.bindingFactory = bindingFactory; 131 this.multibindingDeclarationFactory = multibindingDeclarationFactory; 132 this.bindingDelegateDeclarationFactory = bindingDelegateDeclarationFactory; 133 this.subcomponentDeclarationFactory = subcomponentDeclarationFactory; 134 this.optionalBindingDeclarationFactory = optionalBindingDeclarationFactory; 135 this.superficialValidation = superficialValidation; 136 } 137 create(XTypeElement moduleElement)138 public ModuleDescriptor create(XTypeElement moduleElement) { 139 return reentrantComputeIfAbsent(cache, moduleElement, this::createUncached); 140 } 141 createUncached(XTypeElement moduleElement)142 public ModuleDescriptor createUncached(XTypeElement moduleElement) { 143 ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder(); 144 ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder(); 145 ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations = 146 ImmutableSet.builder(); 147 ImmutableSet.Builder<OptionalBindingDeclaration> optionalDeclarations = 148 ImmutableSet.builder(); 149 150 methodsIn(elements.getAllMembers(toJavac(moduleElement))).stream() 151 .map(method -> toXProcessing(method, processingEnv)) 152 .filter(XElementKt::isMethod) 153 .map(XElements::asMethod) 154 .forEach( 155 moduleMethod -> { 156 if (moduleMethod.hasAnnotation(TypeNames.PROVIDES)) { 157 bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement)); 158 } 159 if (moduleMethod.hasAnnotation(TypeNames.PRODUCES)) { 160 bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement)); 161 } 162 if (moduleMethod.hasAnnotation(TypeNames.BINDS)) { 163 delegates.add( 164 bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement)); 165 } 166 if (moduleMethod.hasAnnotation(TypeNames.MULTIBINDS)) { 167 multibindingDeclarations.add( 168 multibindingDeclarationFactory.forMultibindsMethod( 169 moduleMethod, moduleElement)); 170 } 171 if (moduleMethod.hasAnnotation(TypeNames.BINDS_OPTIONAL_OF)) { 172 optionalDeclarations.add( 173 optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement)); 174 } 175 }); 176 177 moduleElement.getEnclosedTypeElements().stream() 178 .filter(XTypeElement::isCompanionObject) 179 .collect(toOptional()) 180 .ifPresent(companionModule -> collectCompanionModuleBindings(companionModule, bindings)); 181 182 return new AutoValue_ModuleDescriptor( 183 moduleElement, 184 bindings.build(), 185 multibindingDeclarations.build(), 186 subcomponentDeclarationFactory.forModule(moduleElement), 187 delegates.build(), 188 optionalDeclarations.build(), 189 ModuleKind.forAnnotatedElement(moduleElement).get()); 190 } 191 collectCompanionModuleBindings( XTypeElement companionModule, ImmutableSet.Builder<ContributionBinding> bindings)192 private void collectCompanionModuleBindings( 193 XTypeElement companionModule, ImmutableSet.Builder<ContributionBinding> bindings) { 194 ImmutableSet<String> bindingElementDescriptors = 195 bindings.build().stream() 196 .map( 197 binding -> 198 getMethodDescriptor(asExecutable(toJavac(binding.bindingElement().get())))) 199 .collect(toImmutableSet()); 200 201 methodsIn(elements.getAllMembers(toJavac(companionModule))).stream() 202 .map(method -> toXProcessing(method, processingEnv)) 203 .filter(XElementKt::isMethod) 204 .map(XElements::asMethod) 205 // Binding methods in companion objects with @JvmStatic are mirrored in the enclosing 206 // class, therefore we should ignore it or else it'll be a duplicate binding. 207 .filter(method -> !method.hasAnnotation(TypeNames.JVM_STATIC)) 208 // Fallback strategy for de-duping contributing bindings in the companion module with 209 // @JvmStatic by comparing descriptors. Contributing bindings are the only valid bindings 210 // a companion module can declare. See: https://youtrack.jetbrains.com/issue/KT-35104 211 // TODO(danysantiago): Checks qualifiers too. 212 .filter(method -> !bindingElementDescriptors.contains(getMethodDescriptor(method))) 213 .forEach( 214 method -> { 215 if (method.hasAnnotation(TypeNames.PROVIDES)) { 216 bindings.add(bindingFactory.providesMethodBinding(method, companionModule)); 217 } 218 if (method.hasAnnotation(TypeNames.PRODUCES)) { 219 bindings.add(bindingFactory.producesMethodBinding(method, companionModule)); 220 } 221 }); 222 } 223 224 /** Returns all the modules transitively included by given modules, including the arguments. */ transitiveModules(Collection<XTypeElement> modules)225 ImmutableSet<ModuleDescriptor> transitiveModules(Collection<XTypeElement> modules) { 226 // Traverse as a graph to automatically handle modules with cyclic includes. 227 return ImmutableSet.copyOf( 228 Traverser.forGraph( 229 (ModuleDescriptor module) -> transform(includedModules(module), this::create)) 230 .depthFirstPreOrder(transform(modules, this::create))); 231 } 232 includedModules(ModuleDescriptor moduleDescriptor)233 private ImmutableSet<XTypeElement> includedModules(ModuleDescriptor moduleDescriptor) { 234 return ImmutableSet.copyOf( 235 collectIncludedModules(new LinkedHashSet<>(), moduleDescriptor.moduleElement())); 236 } 237 collectIncludedModules( Set<XTypeElement> includedModules, XTypeElement moduleElement)238 private Set<XTypeElement> collectIncludedModules( 239 Set<XTypeElement> includedModules, XTypeElement moduleElement) { 240 XType superclass = moduleElement.getSuperType(); 241 if (superclass != null) { 242 verify(isDeclared(superclass)); 243 if (!TypeName.OBJECT.equals(superclass.getTypeName())) { 244 collectIncludedModules(includedModules, superclass.getTypeElement()); 245 } 246 } 247 moduleAnnotation(moduleElement, superficialValidation) 248 .ifPresent( 249 moduleAnnotation -> { 250 includedModules.addAll(moduleAnnotation.includes()); 251 includedModules.addAll(implicitlyIncludedModules(moduleElement)); 252 }); 253 return includedModules; 254 } 255 256 private static final ClassName CONTRIBUTES_ANDROID_INJECTOR = 257 ClassName.get("dagger.android", "ContributesAndroidInjector"); 258 259 // @ContributesAndroidInjector generates a module that is implicitly included in the enclosing 260 // module implicitlyIncludedModules(XTypeElement module)261 private ImmutableSet<XTypeElement> implicitlyIncludedModules(XTypeElement module) { 262 if (processingEnv.findTypeElement(CONTRIBUTES_ANDROID_INJECTOR) == null) { 263 return ImmutableSet.of(); 264 } 265 return module.getDeclaredMethods().stream() 266 .filter(method -> method.hasAnnotation(CONTRIBUTES_ANDROID_INJECTOR)) 267 .map( 268 method -> 269 DaggerSuperficialValidation.requireTypeElement( 270 processingEnv, implicitlyIncludedModuleName(module, method))) 271 .collect(toImmutableSet()); 272 } 273 implicitlyIncludedModuleName(XTypeElement module, XMethodElement method)274 private ClassName implicitlyIncludedModuleName(XTypeElement module, XMethodElement method) { 275 return ClassName.get( 276 module.getPackageName(), 277 String.format( 278 "%s_%s", 279 classFileName(module.getClassName()), 280 LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(method)))); 281 } 282 283 @Override clearCache()284 public void clearCache() { 285 cache.clear(); 286 } 287 } 288 } 289