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; 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.SourceFiles.simpleVariableName; 23 import static dagger.internal.codegen.Util.componentCanMakeNewInstances; 24 import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent; 25 import static javax.lang.model.element.Modifier.ABSTRACT; 26 import static javax.lang.model.element.Modifier.STATIC; 27 28 import com.google.auto.common.MoreTypes; 29 import com.google.auto.value.AutoValue; 30 import com.google.common.base.Equivalence; 31 import com.google.common.collect.ImmutableSet; 32 import com.squareup.javapoet.ParameterSpec; 33 import com.squareup.javapoet.TypeName; 34 import dagger.Binds; 35 import dagger.BindsOptionalOf; 36 import dagger.Provides; 37 import dagger.internal.codegen.langmodel.DaggerElements; 38 import dagger.internal.codegen.langmodel.DaggerTypes; 39 import dagger.internal.codegen.serialization.ComponentRequirementProto; 40 import dagger.internal.codegen.serialization.ComponentRequirementProto.BoundInstanceRequirement; 41 import dagger.model.BindingKind; 42 import dagger.model.Key; 43 import dagger.multibindings.Multibinds; 44 import dagger.producers.Produces; 45 import java.util.Optional; 46 import javax.lang.model.element.ExecutableElement; 47 import javax.lang.model.element.TypeElement; 48 import javax.lang.model.type.TypeMirror; 49 50 /** A type that a component needs an instance of. */ 51 @AutoValue 52 abstract class ComponentRequirement { 53 enum Kind { 54 /** A type listed in the component's {@code dependencies} attribute. */ 55 DEPENDENCY, 56 57 /** A type listed in the component or subcomponent's {@code modules} attribute. */ 58 MODULE, 59 60 /** 61 * An object that is passed to a builder's {@link dagger.BindsInstance @BindsInstance} method. 62 */ 63 BOUND_INSTANCE, 64 ; 65 isBoundInstance()66 boolean isBoundInstance() { 67 return equals(BOUND_INSTANCE); 68 } 69 isModule()70 boolean isModule() { 71 return equals(MODULE); 72 } 73 } 74 75 /** The kind of requirement. */ kind()76 abstract Kind kind(); 77 78 /** Returns true if this is a {@link Kind#BOUND_INSTANCE} requirement. */ 79 // TODO(ronshapiro): consider removing this and inlining the usages isBoundInstance()80 final boolean isBoundInstance() { 81 return kind().isBoundInstance(); 82 } 83 84 /** 85 * The type of the instance the component must have, wrapped so that requirements can be used as 86 * value types. 87 */ wrappedType()88 abstract Equivalence.Wrapper<TypeMirror> wrappedType(); 89 90 /** The type of the instance the component must have. */ type()91 TypeMirror type() { 92 return wrappedType().get(); 93 } 94 95 /** The element associated with the type of this requirement. */ typeElement()96 TypeElement typeElement() { 97 return MoreTypes.asTypeElement(type()); 98 } 99 100 /** The action a component builder should take if it {@code null} is passed. */ 101 enum NullPolicy { 102 /** Make a new instance. */ 103 NEW, 104 /** Throw an exception. */ 105 THROW, 106 /** Allow use of null values. */ 107 ALLOW, 108 } 109 110 /** 111 * An override for the requirement's null policy. If set, this is used as the null policy instead 112 * of the default behavior in {@link #nullPolicy}. 113 * 114 * <p>Some implementations' null policy can be determined upon construction (e.g., for binding 115 * instances), but others' require Elements and Types, which must wait until {@link #nullPolicy} 116 * is called. 117 */ overrideNullPolicy()118 abstract Optional<NullPolicy> overrideNullPolicy(); 119 120 /** The requirement's null policy. */ nullPolicy(DaggerElements elements, DaggerTypes types)121 NullPolicy nullPolicy(DaggerElements elements, DaggerTypes types) { 122 if (overrideNullPolicy().isPresent()) { 123 return overrideNullPolicy().get(); 124 } 125 switch (kind()) { 126 case MODULE: 127 return componentCanMakeNewInstances(typeElement()) 128 ? NullPolicy.NEW 129 : requiresAPassedInstance(elements, types) ? NullPolicy.THROW : NullPolicy.ALLOW; 130 case DEPENDENCY: 131 case BOUND_INSTANCE: 132 return NullPolicy.THROW; 133 } 134 throw new AssertionError(); 135 } 136 137 /** 138 * Returns true if the passed {@link ComponentRequirement} requires a passed instance in order to 139 * be used within a component. 140 */ requiresAPassedInstance(DaggerElements elements, DaggerTypes types)141 boolean requiresAPassedInstance(DaggerElements elements, DaggerTypes types) { 142 if (!kind().isModule()) { 143 // Bound instances and dependencies always require the user to provide an instance. 144 return true; 145 } 146 return requiresModuleInstance(elements, types) && !componentCanMakeNewInstances(typeElement()); 147 } 148 149 /** 150 * Returns {@code true} if an instance is needed for this (module) requirement. 151 * 152 * <p>An instance is only needed if there is a binding method on the module that is neither {@code 153 * abstract} nor {@code static}; if all bindings are one of those, then there should be no 154 * possible dependency on instance state in the module's bindings. 155 */ requiresModuleInstance(DaggerElements elements, DaggerTypes types)156 private boolean requiresModuleInstance(DaggerElements elements, DaggerTypes types) { 157 ImmutableSet<ExecutableElement> methods = 158 getLocalAndInheritedMethods(typeElement(), types, elements); 159 return methods.stream() 160 .filter(this::isBindingMethod) 161 .map(ExecutableElement::getModifiers) 162 .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC)); 163 } 164 isBindingMethod(ExecutableElement method)165 private boolean isBindingMethod(ExecutableElement method) { 166 // TODO(cgdecker): At the very least, we should have utility methods to consolidate this stuff 167 // in one place; listing individual annotations all over the place is brittle. 168 return isAnyAnnotationPresent( 169 method, 170 Provides.class, 171 Produces.class, 172 // TODO(ronshapiro): it would be cool to have internal meta-annotations that could describe 173 // these, like @AbstractBindingMethod 174 Binds.class, 175 Multibinds.class, 176 BindsOptionalOf.class); 177 } 178 179 /** The key for this requirement, if one is available. */ key()180 abstract Optional<Key> key(); 181 182 /** Returns the name for this requirement that could be used as a variable. */ variableName()183 abstract String variableName(); 184 185 /** Returns a parameter spec for this requirement. */ toParameterSpec()186 ParameterSpec toParameterSpec() { 187 return ParameterSpec.builder(TypeName.get(type()), variableName()).build(); 188 } 189 190 /** Creates a proto representation of this requirement. */ toProto()191 ComponentRequirementProto toProto() { 192 switch (kind()) { 193 case DEPENDENCY: 194 return ComponentRequirementProto.newBuilder() 195 .setDependency(TypeProtoConverter.toProto(type())) 196 .build(); 197 case MODULE: 198 return ComponentRequirementProto.newBuilder() 199 .setModule(TypeProtoConverter.toProto(type())) 200 .build(); 201 case BOUND_INSTANCE: 202 return ComponentRequirementProto.newBuilder() 203 .setBoundInstance( 204 BoundInstanceRequirement.newBuilder() 205 .setKey(KeyFactory.toProto(key().get())) 206 .setNullable(overrideNullPolicy().equals(Optional.of(NullPolicy.ALLOW))) 207 .setVariableName(variableName())) 208 .build(); 209 } 210 throw new AssertionError(this); 211 } 212 forDependency(TypeMirror type)213 static ComponentRequirement forDependency(TypeMirror type) { 214 return new AutoValue_ComponentRequirement( 215 Kind.DEPENDENCY, 216 MoreTypes.equivalence().wrap(checkNotNull(type)), 217 Optional.empty(), 218 Optional.empty(), 219 simpleVariableName(MoreTypes.asTypeElement(type))); 220 } 221 forModule(TypeMirror type)222 static ComponentRequirement forModule(TypeMirror type) { 223 return new AutoValue_ComponentRequirement( 224 Kind.MODULE, 225 MoreTypes.equivalence().wrap(checkNotNull(type)), 226 Optional.empty(), 227 Optional.empty(), 228 simpleVariableName(MoreTypes.asTypeElement(type))); 229 } 230 forBoundInstance(Key key, boolean nullable, String variableName)231 static ComponentRequirement forBoundInstance(Key key, boolean nullable, String variableName) { 232 return new AutoValue_ComponentRequirement( 233 Kind.BOUND_INSTANCE, 234 MoreTypes.equivalence().wrap(key.type()), 235 nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(), 236 Optional.of(key), 237 variableName); 238 } 239 forBoundInstance(ContributionBinding binding)240 static ComponentRequirement forBoundInstance(ContributionBinding binding) { 241 checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE)); 242 return forBoundInstance( 243 binding.key(), 244 binding.nullableType().isPresent(), 245 binding.bindingElement().get().getSimpleName().toString()); 246 } 247 } 248