• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.hilt.processor.internal.definecomponent;
18 
19 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
20 
21 import com.google.auto.value.AutoValue;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableSet;
24 import com.squareup.javapoet.ClassName;
25 import dagger.hilt.processor.internal.AggregatedElements;
26 import dagger.hilt.processor.internal.AnnotationValues;
27 import dagger.hilt.processor.internal.ClassNames;
28 import dagger.hilt.processor.internal.ProcessorErrors;
29 import dagger.hilt.processor.internal.Processors;
30 import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
31 import javax.lang.model.element.AnnotationMirror;
32 import javax.lang.model.element.AnnotationValue;
33 import javax.lang.model.element.TypeElement;
34 import javax.lang.model.util.Elements;
35 
36 /**
37  * A class that represents the values stored in an {@link
38  * dagger.hilt.internal.definecomponent.DefineComponentClasses} annotation.
39  */
40 @AutoValue
41 public abstract class DefineComponentClassesMetadata {
42 
43   /** Returns the aggregating element */
aggregatingElement()44   public abstract TypeElement aggregatingElement();
45 
46   /**
47    * Returns the element annotated with {@code dagger.hilt.internal.definecomponent.DefineComponent}
48    * or {@code dagger.hilt.internal.definecomponent.DefineComponent.Builder}.
49    */
element()50   abstract TypeElement element();
51 
52   /** Returns {@code true} if this element represents a component. */
isComponent()53   abstract boolean isComponent();
54 
55   /** Returns {@code true} if this element represents a component builder. */
isComponentBuilder()56   boolean isComponentBuilder() {
57     return !isComponent();
58   }
59 
60   /** Returns metadata for all aggregated elements in the aggregating package. */
from(Elements elements)61   public static ImmutableSet<DefineComponentClassesMetadata> from(Elements elements) {
62     return from(
63         AggregatedElements.from(
64             ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE,
65             ClassNames.DEFINE_COMPONENT_CLASSES,
66             elements),
67         elements);
68   }
69 
70   /** Returns metadata for each aggregated element. */
from( ImmutableSet<TypeElement> aggregatedElements, Elements elements)71   public static ImmutableSet<DefineComponentClassesMetadata> from(
72       ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
73     return aggregatedElements.stream()
74         .map(aggregatedElement -> create(aggregatedElement, elements))
75         .collect(toImmutableSet());
76   }
77 
create(TypeElement element, Elements elements)78   private static DefineComponentClassesMetadata create(TypeElement element, Elements elements) {
79     AnnotationMirror annotationMirror =
80         Processors.getAnnotationMirror(element, ClassNames.DEFINE_COMPONENT_CLASSES);
81 
82     ImmutableMap<String, AnnotationValue> values =
83         Processors.getAnnotationValues(elements, annotationMirror);
84 
85     String componentName = AnnotationValues.getString(values.get("component"));
86     String builderName = AnnotationValues.getString(values.get("builder"));
87 
88     ProcessorErrors.checkState(
89         !(componentName.isEmpty() && builderName.isEmpty()),
90         element,
91         "@DefineComponentClasses missing both `component` and `builder` members.");
92 
93     ProcessorErrors.checkState(
94         componentName.isEmpty() || builderName.isEmpty(),
95         element,
96         "@DefineComponentClasses should not include both `component` and `builder` members.");
97 
98     boolean isComponent = !componentName.isEmpty();
99     String componentOrBuilderName = isComponent ? componentName : builderName;
100     TypeElement componentOrBuilderElement = elements.getTypeElement(componentOrBuilderName);
101     ProcessorErrors.checkState(
102         componentOrBuilderElement != null,
103         componentOrBuilderElement,
104         "%s.%s(), has invalid value: `%s`.",
105         ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(),
106         isComponent ? "component" : "builder",
107         componentOrBuilderName);
108     return new AutoValue_DefineComponentClassesMetadata(
109         element, componentOrBuilderElement, isComponent);
110   }
111 
toIr(DefineComponentClassesMetadata metadata)112   public static DefineComponentClassesIr toIr(DefineComponentClassesMetadata metadata) {
113     return new DefineComponentClassesIr(
114         ClassName.get(metadata.aggregatingElement()),
115         ClassName.get(metadata.element()));
116   }
117 }
118