1 /* 2 * Copyright (C) 2016 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 com.google.auto.common.MoreElements.getLocalAndInheritedMethods; 20 import static com.google.common.base.Preconditions.checkArgument; 21 import static com.google.common.base.Preconditions.checkNotNull; 22 import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName; 23 import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent; 24 import static javax.lang.model.element.ElementKind.CONSTRUCTOR; 25 import static javax.lang.model.element.Modifier.ABSTRACT; 26 import static javax.lang.model.element.Modifier.PRIVATE; 27 import static javax.lang.model.element.Modifier.STATIC; 28 29 import com.google.auto.common.MoreElements; 30 import com.google.auto.common.MoreTypes; 31 import com.google.auto.value.AutoValue; 32 import com.google.common.base.Equivalence; 33 import com.google.common.collect.ImmutableSet; 34 import com.squareup.javapoet.ParameterSpec; 35 import com.squareup.javapoet.TypeName; 36 import dagger.Binds; 37 import dagger.BindsOptionalOf; 38 import dagger.Provides; 39 import dagger.internal.codegen.kotlin.KotlinMetadataUtil; 40 import dagger.internal.codegen.langmodel.DaggerElements; 41 import dagger.internal.codegen.langmodel.DaggerTypes; 42 import dagger.model.BindingKind; 43 import dagger.model.Key; 44 import dagger.multibindings.Multibinds; 45 import dagger.producers.Produces; 46 import java.util.Optional; 47 import javax.lang.model.element.Element; 48 import javax.lang.model.element.ExecutableElement; 49 import javax.lang.model.element.TypeElement; 50 import javax.lang.model.type.TypeMirror; 51 52 /** A type that a component needs an instance of. */ 53 @AutoValue 54 public abstract class ComponentRequirement { 55 /** The kind of the {@link ComponentRequirement}. */ 56 public enum Kind { 57 /** A type listed in the component's {@code dependencies} attribute. */ 58 DEPENDENCY, 59 60 /** A type listed in the component or subcomponent's {@code modules} attribute. */ 61 MODULE, 62 63 /** 64 * An object that is passed to a builder's {@link dagger.BindsInstance @BindsInstance} method. 65 */ 66 BOUND_INSTANCE, 67 ; 68 isBoundInstance()69 public boolean isBoundInstance() { 70 return equals(BOUND_INSTANCE); 71 } 72 isModule()73 public boolean isModule() { 74 return equals(MODULE); 75 } 76 } 77 78 /** The kind of requirement. */ kind()79 public abstract Kind kind(); 80 81 /** Returns true if this is a {@link Kind#BOUND_INSTANCE} requirement. */ 82 // TODO(ronshapiro): consider removing this and inlining the usages isBoundInstance()83 final boolean isBoundInstance() { 84 return kind().isBoundInstance(); 85 } 86 87 /** 88 * The type of the instance the component must have, wrapped so that requirements can be used as 89 * value types. 90 */ wrappedType()91 public abstract Equivalence.Wrapper<TypeMirror> wrappedType(); 92 93 /** The type of the instance the component must have. */ type()94 public TypeMirror type() { 95 return wrappedType().get(); 96 } 97 98 /** The element associated with the type of this requirement. */ typeElement()99 public TypeElement typeElement() { 100 return MoreTypes.asTypeElement(type()); 101 } 102 103 /** The action a component builder should take if it {@code null} is passed. */ 104 public enum NullPolicy { 105 /** Make a new instance. */ 106 NEW, 107 /** Throw an exception. */ 108 THROW, 109 /** Allow use of null values. */ 110 ALLOW, 111 } 112 113 /** 114 * An override for the requirement's null policy. If set, this is used as the null policy instead 115 * of the default behavior in {@link #nullPolicy}. 116 * 117 * <p>Some implementations' null policy can be determined upon construction (e.g., for binding 118 * instances), but others' require Elements and Types, which must wait until {@link #nullPolicy} 119 * is called. 120 */ overrideNullPolicy()121 abstract Optional<NullPolicy> overrideNullPolicy(); 122 123 /** The requirement's null policy. */ nullPolicy( DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil)124 public NullPolicy nullPolicy( 125 DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) { 126 if (overrideNullPolicy().isPresent()) { 127 return overrideNullPolicy().get(); 128 } 129 switch (kind()) { 130 case MODULE: 131 return componentCanMakeNewInstances(typeElement(), metadataUtil) 132 ? NullPolicy.NEW 133 : requiresAPassedInstance(elements, types, metadataUtil) 134 ? NullPolicy.THROW 135 : NullPolicy.ALLOW; 136 case DEPENDENCY: 137 case BOUND_INSTANCE: 138 return NullPolicy.THROW; 139 } 140 throw new AssertionError(); 141 } 142 143 /** 144 * Returns true if the passed {@link ComponentRequirement} requires a passed instance in order to 145 * be used within a component. 146 */ requiresAPassedInstance( DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil)147 public boolean requiresAPassedInstance( 148 DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) { 149 if (!kind().isModule()) { 150 // Bound instances and dependencies always require the user to provide an instance. 151 return true; 152 } 153 return requiresModuleInstance(elements, types, metadataUtil) 154 && !componentCanMakeNewInstances(typeElement(), metadataUtil); 155 } 156 157 /** 158 * Returns {@code true} if an instance is needed for this (module) requirement. 159 * 160 * <p>An instance is only needed if there is a binding method on the module that is neither {@code 161 * abstract} nor {@code static}; if all bindings are one of those, then there should be no 162 * possible dependency on instance state in the module's bindings. 163 * 164 * <p>Alternatively, if the module is a Kotlin Object then the binding methods are considered 165 * {@code static}, requiring no module instance. 166 */ requiresModuleInstance( DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil)167 private boolean requiresModuleInstance( 168 DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) { 169 boolean isKotlinObject = 170 metadataUtil.isObjectClass(typeElement()) 171 || metadataUtil.isCompanionObjectClass(typeElement()); 172 if (isKotlinObject) { 173 return false; 174 } 175 176 ImmutableSet<ExecutableElement> methods = 177 getLocalAndInheritedMethods(typeElement(), types, elements); 178 return methods.stream() 179 .filter(this::isBindingMethod) 180 .map(ExecutableElement::getModifiers) 181 .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC)); 182 } 183 isBindingMethod(ExecutableElement method)184 private boolean isBindingMethod(ExecutableElement method) { 185 // TODO(cgdecker): At the very least, we should have utility methods to consolidate this stuff 186 // in one place; listing individual annotations all over the place is brittle. 187 return isAnyAnnotationPresent( 188 method, 189 Provides.class, 190 Produces.class, 191 // TODO(ronshapiro): it would be cool to have internal meta-annotations that could describe 192 // these, like @AbstractBindingMethod 193 Binds.class, 194 Multibinds.class, 195 BindsOptionalOf.class); 196 } 197 198 /** The key for this requirement, if one is available. */ key()199 public abstract Optional<Key> key(); 200 201 /** Returns the name for this requirement that could be used as a variable. */ variableName()202 public abstract String variableName(); 203 204 /** Returns a parameter spec for this requirement. */ toParameterSpec()205 public ParameterSpec toParameterSpec() { 206 return ParameterSpec.builder(TypeName.get(type()), variableName()).build(); 207 } 208 forDependency(TypeMirror type)209 public static ComponentRequirement forDependency(TypeMirror type) { 210 return new AutoValue_ComponentRequirement( 211 Kind.DEPENDENCY, 212 MoreTypes.equivalence().wrap(checkNotNull(type)), 213 Optional.empty(), 214 Optional.empty(), 215 simpleVariableName(MoreTypes.asTypeElement(type))); 216 } 217 forModule(TypeMirror type)218 public static ComponentRequirement forModule(TypeMirror type) { 219 return new AutoValue_ComponentRequirement( 220 Kind.MODULE, 221 MoreTypes.equivalence().wrap(checkNotNull(type)), 222 Optional.empty(), 223 Optional.empty(), 224 simpleVariableName(MoreTypes.asTypeElement(type))); 225 } 226 forBoundInstance(Key key, boolean nullable, String variableName)227 static ComponentRequirement forBoundInstance(Key key, boolean nullable, String variableName) { 228 return new AutoValue_ComponentRequirement( 229 Kind.BOUND_INSTANCE, 230 MoreTypes.equivalence().wrap(key.type()), 231 nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(), 232 Optional.of(key), 233 variableName); 234 } 235 forBoundInstance(ContributionBinding binding)236 public static ComponentRequirement forBoundInstance(ContributionBinding binding) { 237 checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE)); 238 return forBoundInstance( 239 binding.key(), 240 binding.nullableType().isPresent(), 241 binding.bindingElement().get().getSimpleName().toString()); 242 } 243 244 /** 245 * Returns true if and only if a component can instantiate new instances (typically of a module) 246 * rather than requiring that they be passed. 247 */ 248 // TODO(bcorso): Should this method throw if its called knowing that an instance is not needed? componentCanMakeNewInstances( TypeElement typeElement, KotlinMetadataUtil metadataUtil)249 public static boolean componentCanMakeNewInstances( 250 TypeElement typeElement, KotlinMetadataUtil metadataUtil) { 251 switch (typeElement.getKind()) { 252 case CLASS: 253 break; 254 case ENUM: 255 case ANNOTATION_TYPE: 256 case INTERFACE: 257 return false; 258 default: 259 throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind()); 260 } 261 262 if (typeElement.getModifiers().contains(ABSTRACT)) { 263 return false; 264 } 265 266 if (requiresEnclosingInstance(typeElement)) { 267 return false; 268 } 269 270 if (metadataUtil.isObjectClass(typeElement) 271 || metadataUtil.isCompanionObjectClass(typeElement)) { 272 return false; 273 } 274 275 for (Element enclosed : typeElement.getEnclosedElements()) { 276 if (enclosed.getKind().equals(CONSTRUCTOR) 277 && MoreElements.asExecutable(enclosed).getParameters().isEmpty() 278 && !enclosed.getModifiers().contains(PRIVATE)) { 279 return true; 280 } 281 } 282 283 // TODO(gak): still need checks for visibility 284 285 return false; 286 } 287 requiresEnclosingInstance(TypeElement typeElement)288 private static boolean requiresEnclosingInstance(TypeElement typeElement) { 289 switch (typeElement.getNestingKind()) { 290 case TOP_LEVEL: 291 return false; 292 case MEMBER: 293 return !typeElement.getModifiers().contains(STATIC); 294 case ANONYMOUS: 295 case LOCAL: 296 return true; 297 } 298 throw new AssertionError( 299 "TypeElement cannot have nesting kind: " + typeElement.getNestingKind()); 300 } 301 } 302