• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.common.base.Preconditions.checkArgument;
20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
21 
22 import androidx.room.compiler.processing.XAnnotation;
23 import androidx.room.compiler.processing.XTypeElement;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.Sets;
26 import com.squareup.javapoet.ClassName;
27 import dagger.internal.codegen.javapoet.TypeNames;
28 import java.util.EnumSet;
29 import java.util.Optional;
30 import java.util.Set;
31 
32 /** Enumeration of the kinds of modules. */
33 public enum ModuleKind {
34   /** {@code @Module} */
35   MODULE(TypeNames.MODULE),
36 
37   /** {@code @ProducerModule} */
38   PRODUCER_MODULE(TypeNames.PRODUCER_MODULE);
39 
40   /** Returns the annotations for modules of the given kinds. */
annotationsFor(Set<ModuleKind> kinds)41   private static ImmutableSet<ClassName> annotationsFor(Set<ModuleKind> kinds) {
42     return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
43   }
44 
45   /**
46    * Returns the kind of an annotated element if it is annotated with one of the module {@linkplain
47    * #annotation() annotations}.
48    *
49    * @throws IllegalArgumentException if the element is annotated with more than one of the module
50    *     annotations
51    */
forAnnotatedElement(XTypeElement element)52   public static Optional<ModuleKind> forAnnotatedElement(XTypeElement element) {
53     Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class);
54     for (ModuleKind kind : values()) {
55       if (element.hasAnnotation(kind.annotation())) {
56         kinds.add(kind);
57       }
58     }
59 
60     if (kinds.size() > 1) {
61       throw new IllegalArgumentException(
62           element + " cannot be annotated with more than one of " + annotationsFor(kinds));
63     }
64     return kinds.stream().findAny();
65   }
66 
checkIsModule(XTypeElement moduleElement)67   public static void checkIsModule(XTypeElement moduleElement) {
68     // If the type element is a Kotlin companion object, then assert it is a module if its enclosing
69     // type is a module.
70     if (moduleElement.isCompanionObject()) {
71       checkArgument(forAnnotatedElement(moduleElement.getEnclosingTypeElement()).isPresent());
72     } else {
73       checkArgument(forAnnotatedElement(moduleElement).isPresent());
74     }
75   }
76 
77   private final ClassName moduleAnnotation;
78 
ModuleKind(ClassName moduleAnnotation)79   ModuleKind(ClassName moduleAnnotation) {
80     this.moduleAnnotation = moduleAnnotation;
81   }
82 
83   /**
84    * Returns the annotation mirror for this module kind on the given type.
85    *
86    * @throws IllegalArgumentException if the annotation is not present on the type
87    */
getModuleAnnotation(XTypeElement element)88   public XAnnotation getModuleAnnotation(XTypeElement element) {
89     checkArgument(
90         element.hasAnnotation(moduleAnnotation),
91         "annotation %s is not present on type %s",
92         moduleAnnotation,
93         element);
94     return element.getAnnotation(moduleAnnotation);
95   }
96 
97   /** Returns the annotation that marks a module of this kind. */
annotation()98   public ClassName annotation() {
99     return moduleAnnotation;
100   }
101 
102   /** Returns the kinds of modules that a module of this kind is allowed to include. */
legalIncludedModuleKinds()103   public ImmutableSet<ModuleKind> legalIncludedModuleKinds() {
104     switch (this) {
105       case MODULE:
106         return Sets.immutableEnumSet(MODULE);
107       case PRODUCER_MODULE:
108         return Sets.immutableEnumSet(MODULE, PRODUCER_MODULE);
109     }
110     throw new AssertionError(this);
111   }
112 }
113