1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.AnnotationMirrors; 19 import com.google.auto.common.MoreElements; 20 import com.google.auto.common.MoreTypes; 21 import com.google.auto.value.AutoValue; 22 import com.google.common.base.Equivalence; 23 import com.google.common.base.MoreObjects; 24 import com.google.common.base.Optional; 25 import com.google.common.collect.Iterables; 26 import com.google.common.util.concurrent.ListenableFuture; 27 import dagger.Provides; 28 import dagger.producers.Produced; 29 import dagger.producers.Producer; 30 import dagger.producers.Produces; 31 import java.util.Map; 32 import java.util.Set; 33 import javax.inject.Provider; 34 import javax.inject.Qualifier; 35 import javax.lang.model.element.AnnotationMirror; 36 import javax.lang.model.element.ElementKind; 37 import javax.lang.model.element.ExecutableElement; 38 import javax.lang.model.element.Modifier; 39 import javax.lang.model.element.TypeElement; 40 import javax.lang.model.type.DeclaredType; 41 import javax.lang.model.type.ExecutableType; 42 import javax.lang.model.type.PrimitiveType; 43 import javax.lang.model.type.TypeKind; 44 import javax.lang.model.type.TypeMirror; 45 import javax.lang.model.util.Elements; 46 import javax.lang.model.util.SimpleTypeVisitor6; 47 import javax.lang.model.util.Types; 48 49 import static com.google.auto.common.MoreTypes.asExecutable; 50 import static com.google.common.base.Preconditions.checkArgument; 51 import static com.google.common.base.Preconditions.checkNotNull; 52 import static dagger.internal.codegen.InjectionAnnotations.getQualifier; 53 import static dagger.internal.codegen.MapKeys.getMapKey; 54 import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType; 55 import static dagger.internal.codegen.Util.unwrapOptionalEquivalence; 56 import static dagger.internal.codegen.Util.wrapOptionalInEquivalence; 57 import static javax.lang.model.element.ElementKind.METHOD; 58 59 /** 60 * Represents a unique combination of {@linkplain TypeMirror type} and 61 * {@linkplain Qualifier qualifier} to which binding can occur. 62 * 63 * @author Gregory Kick 64 */ 65 @AutoValue 66 abstract class Key { 67 /** 68 * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix 69 * for the type of this key. 70 * 71 * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented 72 * to represent logical equality, so {@link AnnotationMirrors#equivalence()} 73 * provides this facility. 74 */ wrappedQualifier()75 abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier(); 76 77 /** 78 * The type represented by this key. 79 * 80 * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent 81 * logical equality, so {@link MoreTypes#equivalence()} wraps this type. 82 */ wrappedType()83 abstract Equivalence.Wrapper<TypeMirror> wrappedType(); 84 qualifier()85 Optional<AnnotationMirror> qualifier() { 86 return unwrapOptionalEquivalence(wrappedQualifier()); 87 } 88 type()89 TypeMirror type() { 90 return wrappedType().get(); 91 } 92 normalize(Types types, TypeMirror type)93 private static TypeMirror normalize(Types types, TypeMirror type) { 94 TypeKind kind = type.getKind(); 95 return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type; 96 } 97 withType(Types types, TypeMirror newType)98 Key withType(Types types, TypeMirror newType) { 99 return new AutoValue_Key(wrappedQualifier(), 100 MoreTypes.equivalence().wrap(normalize(types, newType))); 101 } 102 isValidMembersInjectionKey()103 boolean isValidMembersInjectionKey() { 104 return !qualifier().isPresent(); 105 } 106 107 /** 108 * Returns true if the key is valid as an implicit key (that is, if it's valid for a just-in-time 109 * binding by discovering an {@code @Inject} constructor). 110 */ isValidImplicitProvisionKey(final Types types)111 boolean isValidImplicitProvisionKey(final Types types) { 112 // Qualifiers disqualify implicit provisioning. 113 if (qualifier().isPresent()) { 114 return false; 115 } 116 117 return type().accept(new SimpleTypeVisitor6<Boolean, Void>() { 118 @Override protected Boolean defaultAction(TypeMirror e, Void p) { 119 return false; // Only declared types are allowed. 120 } 121 122 @Override public Boolean visitDeclared(DeclaredType type, Void ignored) { 123 // Non-classes or abstract classes aren't allowed. 124 TypeElement element = MoreElements.asType(type.asElement()); 125 if (!element.getKind().equals(ElementKind.CLASS) 126 || element.getModifiers().contains(Modifier.ABSTRACT)) { 127 return false; 128 } 129 130 // If the key has type arguments, validate that each type argument is declared. 131 // Otherwise the type argument may be a wildcard (or other type), and we can't 132 // resolve that to actual types. 133 for (TypeMirror arg : type.getTypeArguments()) { 134 if (arg.getKind() != TypeKind.DECLARED) { 135 return false; 136 } 137 } 138 139 // Also validate that the key is not the erasure of a generic type. 140 // If it is, that means the user referred to Foo<T> as just 'Foo', 141 // which we don't allow. (This is a judgement call -- we *could* 142 // allow it and instantiate the type bounds... but we don't.) 143 return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty() 144 || !types.isSameType(types.erasure(element.asType()), type()); 145 } 146 }, null); 147 } 148 149 @Override 150 public String toString() { 151 return MoreObjects.toStringHelper(Key.class) 152 .omitNullValues() 153 .add("qualifier", qualifier().orNull()) 154 .add("type", type()) 155 .toString(); 156 } 157 158 static final class Factory { 159 private final Types types; 160 private final Elements elements; 161 162 Factory(Types types, Elements elements) { 163 this.types = checkNotNull(types); 164 this.elements = checkNotNull(elements); 165 } 166 167 private TypeElement getSetElement() { 168 return elements.getTypeElement(Set.class.getCanonicalName()); 169 } 170 171 private TypeElement getMapElement() { 172 return elements.getTypeElement(Map.class.getCanonicalName()); 173 } 174 175 private TypeElement getProviderElement() { 176 return elements.getTypeElement(Provider.class.getCanonicalName()); 177 } 178 179 private TypeElement getProducerElement() { 180 return elements.getTypeElement(Producer.class.getCanonicalName()); 181 } 182 183 private TypeElement getClassElement(Class<?> cls) { 184 return elements.getTypeElement(cls.getCanonicalName()); 185 } 186 187 Key forComponentMethod(ExecutableElement componentMethod) { 188 checkNotNull(componentMethod); 189 checkArgument(componentMethod.getKind().equals(METHOD)); 190 TypeMirror returnType = normalize(types, componentMethod.getReturnType()); 191 return forMethod(componentMethod, returnType); 192 } 193 194 Key forProductionComponentMethod(ExecutableElement componentMethod) { 195 checkNotNull(componentMethod); 196 checkArgument(componentMethod.getKind().equals(METHOD)); 197 TypeMirror returnType = normalize(types, componentMethod.getReturnType()); 198 TypeMirror keyType = returnType; 199 if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) { 200 keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); 201 } 202 return forMethod(componentMethod, keyType); 203 } 204 205 Key forSubcomponentBuilderMethod( 206 ExecutableElement subcomponentBuilderMethod, DeclaredType declaredContainer) { 207 checkNotNull(subcomponentBuilderMethod); 208 checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD)); 209 ExecutableType resolvedMethod = 210 asExecutable(types.asMemberOf(declaredContainer, subcomponentBuilderMethod)); 211 TypeMirror returnType = normalize(types, resolvedMethod.getReturnType()); 212 return forMethod(subcomponentBuilderMethod, returnType); 213 } 214 215 Key forProvidesMethod(ExecutableType executableType, ExecutableElement method) { 216 checkNotNull(method); 217 checkArgument(method.getKind().equals(METHOD)); 218 Provides providesAnnotation = method.getAnnotation(Provides.class); 219 checkArgument(providesAnnotation != null); 220 TypeMirror returnType = normalize(types, executableType.getReturnType()); 221 TypeMirror keyType = 222 providesOrProducesKeyType( 223 returnType, 224 method, 225 Optional.of(providesAnnotation.type()), 226 Optional.<Produces.Type>absent()); 227 return forMethod(method, keyType); 228 } 229 230 // TODO(user): Reconcile this method with forProvidesMethod when Provides.Type and 231 // Produces.Type are no longer different. 232 Key forProducesMethod(ExecutableType executableType, ExecutableElement method) { 233 checkNotNull(method); 234 checkArgument(method.getKind().equals(METHOD)); 235 Produces producesAnnotation = method.getAnnotation(Produces.class); 236 checkArgument(producesAnnotation != null); 237 TypeMirror returnType = normalize(types, executableType.getReturnType()); 238 TypeMirror unfuturedType = returnType; 239 if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) { 240 unfuturedType = 241 Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); 242 } 243 TypeMirror keyType = 244 providesOrProducesKeyType( 245 unfuturedType, 246 method, 247 Optional.<Provides.Type>absent(), 248 Optional.of(producesAnnotation.type())); 249 return forMethod(method, keyType); 250 } 251 252 private TypeMirror providesOrProducesKeyType( 253 TypeMirror returnType, 254 ExecutableElement method, 255 Optional<Provides.Type> providesType, 256 Optional<Produces.Type> producesType) { 257 switch (providesType.isPresent() 258 ? providesType.get() 259 : Provides.Type.valueOf(producesType.get().name())) { 260 case UNIQUE: 261 return returnType; 262 case SET: 263 return types.getDeclaredType(getSetElement(), returnType); 264 case MAP: 265 return mapOfFactoryType( 266 method, 267 returnType, 268 providesType.isPresent() ? getProviderElement() : getProducerElement()); 269 case SET_VALUES: 270 // TODO(gak): do we want to allow people to use "covariant return" here? 271 checkArgument(MoreTypes.isType(returnType) && MoreTypes.isTypeOf(Set.class, returnType)); 272 return returnType; 273 default: 274 throw new AssertionError(); 275 } 276 } 277 278 private TypeMirror mapOfFactoryType( 279 ExecutableElement method, TypeMirror valueType, TypeElement factoryType) { 280 TypeMirror mapKeyType = mapKeyType(method); 281 TypeMirror mapValueFactoryType = types.getDeclaredType(factoryType, valueType); 282 return types.getDeclaredType(getMapElement(), mapKeyType, mapValueFactoryType); 283 } 284 285 private TypeMirror mapKeyType(ExecutableElement method) { 286 AnnotationMirror mapKeyAnnotation = getMapKey(method).get(); 287 return MapKeys.unwrapValue(mapKeyAnnotation).isPresent() 288 ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types) 289 : mapKeyAnnotation.getAnnotationType(); 290 } 291 292 private Key forMethod(ExecutableElement method, TypeMirror keyType) { 293 return new AutoValue_Key( 294 wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(method)), 295 MoreTypes.equivalence().wrap(keyType)); 296 } 297 298 Key forInjectConstructorWithResolvedType(TypeMirror type) { 299 return new AutoValue_Key( 300 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 301 MoreTypes.equivalence().wrap(type)); 302 } 303 304 Key forComponent(TypeMirror type) { 305 return new AutoValue_Key( 306 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 307 MoreTypes.equivalence().wrap(normalize(types, type))); 308 } 309 310 Key forMembersInjectedType(TypeMirror type) { 311 return new AutoValue_Key( 312 Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(), 313 MoreTypes.equivalence().wrap(normalize(types, type))); 314 } 315 316 Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) { 317 return new AutoValue_Key( 318 wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier), 319 MoreTypes.equivalence().wrap(normalize(types, type))); 320 } 321 322 /** 323 * Optionally extract a {@link Key} for the underlying provision binding(s) if such a 324 * valid key can be inferred from the given key. Specifically, if the key represents a 325 * {@link Map}{@code <K, V>}, a key of {@code Map<K, Provider<V>>} will be returned. 326 */ 327 Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) { 328 return maybeWrapMapValue(possibleMapKey, Provider.class); 329 } 330 331 /** 332 * Optionally extract a {@link Key} for the underlying production binding(s) if such a 333 * valid key can be inferred from the given key. Specifically, if the key represents a 334 * {@link Map}{@code <K, V>}, a key of {@code Map<K, Producer<V>>} will be returned. 335 */ 336 Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) { 337 return maybeWrapMapValue(possibleMapKey, Producer.class); 338 } 339 340 /** 341 * Returns a key of {@link Map}{@code <K, WrappingClass<V>>} if the input key represents a 342 * {@code Map<K, V>}. 343 */ 344 private Optional<Key> maybeWrapMapValue(Key possibleMapKey, Class<?> wrappingClass) { 345 if (MoreTypes.isTypeOf(Map.class, possibleMapKey.type())) { 346 DeclaredType declaredMapType = MoreTypes.asDeclared(possibleMapKey.type()); 347 TypeMirror mapValueType = Util.getValueTypeOfMap(declaredMapType); 348 if (!MoreTypes.isTypeOf(wrappingClass, mapValueType)) { 349 TypeMirror keyType = Util.getKeyTypeOfMap(declaredMapType); 350 TypeElement wrappingElement = getClassElement(wrappingClass); 351 if (wrappingElement == null) { 352 // This target might not be compiled with Producers, so wrappingClass might not have an 353 // associated element. 354 return Optional.absent(); 355 } 356 DeclaredType wrappedType = types.getDeclaredType(wrappingElement, mapValueType); 357 TypeMirror mapType = types.getDeclaredType(getMapElement(), keyType, wrappedType); 358 return Optional.<Key>of(new AutoValue_Key( 359 possibleMapKey.wrappedQualifier(), 360 MoreTypes.equivalence().wrap(mapType))); 361 } 362 } 363 return Optional.absent(); 364 } 365 366 /** 367 * Optionally extract a {@link Key} for a {@code Set<T>} if the given key is for 368 * {@code Set<Produced<T>>}. 369 */ 370 Optional<Key> implicitSetKeyFromProduced(Key possibleSetOfProducedKey) { 371 if (MoreTypes.isTypeOf(Set.class, possibleSetOfProducedKey.type())) { 372 TypeMirror argType = 373 MoreTypes.asDeclared(possibleSetOfProducedKey.type()).getTypeArguments().get(0); 374 if (MoreTypes.isTypeOf(Produced.class, argType)) { 375 TypeMirror producedArgType = MoreTypes.asDeclared(argType).getTypeArguments().get(0); 376 TypeMirror setType = types.getDeclaredType(getSetElement(), producedArgType); 377 return Optional.of(possibleSetOfProducedKey.withType(types, setType)); 378 } 379 } 380 return Optional.absent(); 381 } 382 } 383 } 384