• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.base;
18 
19 import static com.google.auto.common.MoreTypes.asTypeElement;
20 import static dagger.internal.codegen.base.ComponentAnnotation.allComponentAndCreatorAnnotations;
21 import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
22 
23 import com.google.auto.common.MoreElements;
24 import com.google.auto.common.MoreTypes;
25 import dagger.internal.codegen.langmodel.DaggerTypes;
26 import dagger.model.Key;
27 import java.util.Optional;
28 import javax.lang.model.element.AnnotationMirror;
29 import javax.lang.model.element.ElementKind;
30 import javax.lang.model.element.Modifier;
31 import javax.lang.model.element.TypeElement;
32 import javax.lang.model.type.DeclaredType;
33 import javax.lang.model.type.TypeKind;
34 import javax.lang.model.type.TypeMirror;
35 import javax.lang.model.util.SimpleTypeVisitor6;
36 
37 /** Utility methods related to {@link Key}s. */
38 public final class Keys {
isValidMembersInjectionKey(Key key)39   public static boolean isValidMembersInjectionKey(Key key) {
40     return !key.qualifier().isPresent()
41         && !key.multibindingContributionIdentifier().isPresent()
42         && key.type().getKind().equals(TypeKind.DECLARED);
43   }
44 
45   /**
46    * Returns {@code true} if this is valid as an implicit key (that is, if it's valid for a
47    * just-in-time binding by discovering an {@code @Inject} constructor).
48    */
isValidImplicitProvisionKey(Key key, DaggerTypes types)49   public static boolean isValidImplicitProvisionKey(Key key, DaggerTypes types) {
50     return isValidImplicitProvisionKey(key.qualifier(), key.type(), types);
51   }
52 
53   /**
54    * Returns {@code true} if a key with {@code qualifier} and {@code type} is valid as an implicit
55    * key (that is, if it's valid for a just-in-time binding by discovering an {@code @Inject}
56    * constructor).
57    */
isValidImplicitProvisionKey( Optional<? extends AnnotationMirror> qualifier, TypeMirror type, final DaggerTypes types)58   public static boolean isValidImplicitProvisionKey(
59       Optional<? extends AnnotationMirror> qualifier, TypeMirror type, final DaggerTypes types) {
60     // Qualifiers disqualify implicit provisioning.
61     if (qualifier.isPresent()) {
62       return false;
63     }
64 
65     return type.accept(
66         new SimpleTypeVisitor6<Boolean, Void>(false) {
67           @Override
68           public Boolean visitDeclared(DeclaredType type, Void ignored) {
69             // Non-classes or abstract classes aren't allowed.
70             TypeElement element = MoreElements.asType(type.asElement());
71             if (!element.getKind().equals(ElementKind.CLASS)
72                 || element.getModifiers().contains(Modifier.ABSTRACT)) {
73               return false;
74             }
75 
76             // If the key has type arguments, validate that each type argument is declared.
77             // Otherwise the type argument may be a wildcard (or other type), and we can't
78             // resolve that to actual types.
79             for (TypeMirror arg : type.getTypeArguments()) {
80               if (arg.getKind() != TypeKind.DECLARED) {
81                 return false;
82               }
83             }
84 
85             // Also validate that the key is not the erasure of a generic type.
86             // If it is, that means the user referred to Foo<T> as just 'Foo',
87             // which we don't allow.  (This is a judgement call -- we *could*
88             // allow it and instantiate the type bounds... but we don't.)
89             return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
90                 || !types.isSameType(types.erasure(element.asType()), type);
91           }
92         },
93         null);
94   }
95 
96   /**
97    * Returns {@code true} if the given key is for a component/subcomponent or a creator of a
98    * component/subcomponent.
99    */
100   public static boolean isComponentOrCreator(Key key) {
101     return !key.qualifier().isPresent()
102         && key.type().getKind() == TypeKind.DECLARED
103         && isAnyAnnotationPresent(asTypeElement(key.type()), allComponentAndCreatorAnnotations());
104   }
105 }
106