1 /* 2 * Copyright (C) 2014 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.common.base.Preconditions.checkState; 20 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.CLASS_CONSTRUCTOR; 21 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.DELEGATE; 22 import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE; 23 import static dagger.internal.codegen.MapKeys.unwrapValue; 24 import static dagger.internal.codegen.MoreAnnotationMirrors.unwrapOptionalEquivalence; 25 import static java.util.Arrays.asList; 26 27 import com.google.auto.common.MoreElements; 28 import com.google.common.base.Equivalence; 29 import com.google.errorprone.annotations.CanIgnoreReturnValue; 30 import com.google.errorprone.annotations.CheckReturnValue; 31 import dagger.internal.codegen.ContributionType.HasContributionType; 32 import dagger.model.BindingKind; 33 import dagger.model.DependencyRequest; 34 import dagger.model.Key; 35 import java.util.Optional; 36 import javax.lang.model.element.AnnotationMirror; 37 import javax.lang.model.element.AnnotationValue; 38 import javax.lang.model.element.Element; 39 import javax.lang.model.element.ExecutableElement; 40 import javax.lang.model.element.TypeElement; 41 import javax.lang.model.type.DeclaredType; 42 import javax.lang.model.type.TypeMirror; 43 44 /** 45 * An abstract class for a value object representing the mechanism by which a {@link Key} can be 46 * contributed to a dependency graph. 47 */ 48 abstract class ContributionBinding extends Binding implements HasContributionType { 49 50 /** Returns the type that specifies this' nullability, absent if not nullable. */ nullableType()51 abstract Optional<DeclaredType> nullableType(); 52 wrappedMapKeyAnnotation()53 abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation(); 54 mapKeyAnnotation()55 final Optional<AnnotationMirror> mapKeyAnnotation() { 56 return unwrapOptionalEquivalence(wrappedMapKeyAnnotation()); 57 } 58 59 /** 60 * If this is a map contribution, returns the key of its map entry. 61 * 62 * @throws IllegalStateException if {@link #mapKeyAnnotation()} returns an empty value. 63 */ mapKey()64 final Object mapKey() { 65 checkState(mapKeyAnnotation().isPresent()); 66 AnnotationMirror mapKeyAnnotation = mapKeyAnnotation().get(); 67 return unwrapValue(mapKeyAnnotation).map(AnnotationValue::getValue).orElse(mapKeyAnnotation); 68 } 69 70 /** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */ contributedPrimitiveType()71 final Optional<TypeMirror> contributedPrimitiveType() { 72 return bindingElement() 73 .filter(bindingElement -> bindingElement instanceof ExecutableElement) 74 .map(bindingElement -> MoreElements.asExecutable(bindingElement).getReturnType()) 75 .filter(type -> type.getKind().isPrimitive()); 76 } 77 78 @Override isNullable()79 public final boolean isNullable() { 80 return nullableType().isPresent(); 81 } 82 83 /** 84 * The strategy for getting an instance of a factory for a {@link ContributionBinding}. 85 */ 86 enum FactoryCreationStrategy { 87 /** The factory class is a single instance. */ 88 SINGLETON_INSTANCE, 89 /** The factory must be created by calling the constructor. */ 90 CLASS_CONSTRUCTOR, 91 /** The factory is simply delegated to another. */ 92 DELEGATE, 93 } 94 95 /** 96 * Returns the {@link FactoryCreationStrategy} appropriate for a binding. 97 * 98 * <p>Delegate bindings use the {@link FactoryCreationStrategy#DELEGATE} strategy. 99 * 100 * <p>Bindings without dependencies that don't require a module instance use the {@link 101 * FactoryCreationStrategy#SINGLETON_INSTANCE} strategy. 102 * 103 * <p>All other bindings use the {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR} strategy. 104 */ factoryCreationStrategy()105 final FactoryCreationStrategy factoryCreationStrategy() { 106 switch (kind()) { 107 case DELEGATE: 108 return DELEGATE; 109 case PROVISION: 110 return dependencies().isEmpty() && !requiresModuleInstance() 111 ? SINGLETON_INSTANCE 112 : CLASS_CONSTRUCTOR; 113 case INJECTION: 114 case MULTIBOUND_SET: 115 case MULTIBOUND_MAP: 116 return dependencies().isEmpty() ? SINGLETON_INSTANCE : CLASS_CONSTRUCTOR; 117 default: 118 return CLASS_CONSTRUCTOR; 119 } 120 } 121 122 /** 123 * The {@link TypeMirror type} for the {@code Factory<T>} or {@code Producer<T>} which is created 124 * for this binding. Uses the binding's key, V in the case of {@code Map<K, FrameworkClass<V>>>}, 125 * and E {@code Set<E>} for {@link dagger.multibindings.IntoSet @IntoSet} methods. 126 */ contributedType()127 final TypeMirror contributedType() { 128 switch (contributionType()) { 129 case MAP: 130 return MapType.from(key()).unwrappedFrameworkValueType(); 131 case SET: 132 return SetType.from(key()).elementType(); 133 case SET_VALUES: 134 case UNIQUE: 135 return key().type(); 136 } 137 throw new AssertionError(); 138 } 139 isSyntheticMultibinding()140 final boolean isSyntheticMultibinding() { 141 switch (kind()) { 142 case MULTIBOUND_SET: 143 case MULTIBOUND_MAP: 144 return true; 145 default: 146 return false; 147 } 148 } 149 150 /** Whether the bound type has a generated implementation. */ requiresGeneratedInstance()151 final boolean requiresGeneratedInstance() { 152 switch (kind()) { 153 case COMPONENT: 154 case SUBCOMPONENT_CREATOR: 155 return true; 156 default: 157 return false; 158 } 159 } 160 161 /** 162 * Returns {@link BindingKind#MULTIBOUND_SET} or {@link 163 * BindingKind#MULTIBOUND_MAP} if the key is a set or map. 164 * 165 * @throws IllegalArgumentException if {@code key} is neither a set nor a map 166 */ bindingKindForMultibindingKey(Key key)167 static BindingKind bindingKindForMultibindingKey(Key key) { 168 if (SetType.isSet(key)) { 169 return BindingKind.MULTIBOUND_SET; 170 } else if (MapType.isMap(key)) { 171 return BindingKind.MULTIBOUND_MAP; 172 } else { 173 throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key)); 174 } 175 } 176 177 /** 178 * Base builder for {@link com.google.auto.value.AutoValue @AutoValue} subclasses of {@link 179 * ContributionBinding}. 180 */ 181 @CanIgnoreReturnValue 182 abstract static class Builder<C extends ContributionBinding, B extends Builder<C, B>> { dependencies(Iterable<DependencyRequest> dependencies)183 abstract B dependencies(Iterable<DependencyRequest> dependencies); 184 dependencies(DependencyRequest... dependencies)185 B dependencies(DependencyRequest... dependencies) { 186 return dependencies(asList(dependencies)); 187 } 188 unresolved(C unresolved)189 abstract B unresolved(C unresolved); 190 contributionType(ContributionType contributionType)191 abstract B contributionType(ContributionType contributionType); 192 bindingElement(Element bindingElement)193 abstract B bindingElement(Element bindingElement); 194 contributingModule(TypeElement contributingModule)195 abstract B contributingModule(TypeElement contributingModule); 196 key(Key key)197 abstract B key(Key key); 198 nullableType(Optional<DeclaredType> nullableType)199 abstract B nullableType(Optional<DeclaredType> nullableType); 200 wrappedMapKeyAnnotation( Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation)201 abstract B wrappedMapKeyAnnotation( 202 Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation); 203 kind(BindingKind kind)204 abstract B kind(BindingKind kind); 205 206 @CheckReturnValue build()207 abstract C build(); 208 } 209 } 210