• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BasicAnnotationProcessor.ProcessingStep;
19 import com.google.auto.common.MoreElements;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.common.collect.Maps;
22 import com.google.common.collect.SetMultimap;
23 import dagger.Component;
24 import dagger.Subcomponent;
25 import dagger.internal.codegen.ComponentDescriptor.Factory;
26 import dagger.internal.codegen.ComponentValidator.ComponentValidationReport;
27 import java.lang.annotation.Annotation;
28 import java.util.Map;
29 import java.util.Set;
30 import javax.annotation.processing.Messager;
31 import javax.lang.model.element.Element;
32 import javax.lang.model.element.TypeElement;
33 
34 /**
35  * A {@link ProcessingStep} that is responsible for dealing with the {@link Component} annotation
36  * as part of the {@link ComponentProcessor}.
37  *
38  * @author Gregory Kick
39  */
40 final class ComponentProcessingStep extends AbstractComponentProcessingStep {
41   private final Messager messager;
42   private final ComponentValidator componentValidator;
43   private final ComponentValidator subcomponentValidator;
44   private final BuilderValidator componentBuilderValidator;
45   private final BuilderValidator subcomponentBuilderValidator;
46 
ComponentProcessingStep( Messager messager, ComponentValidator componentValidator, ComponentValidator subcomponentValidator, BuilderValidator componentBuilderValidator, BuilderValidator subcomponentBuilderValidator, ComponentHierarchyValidator componentHierarchyValidator, BindingGraphValidator bindingGraphValidator, Factory componentDescriptorFactory, BindingGraph.Factory bindingGraphFactory, ComponentGenerator componentGenerator)47   ComponentProcessingStep(
48       Messager messager,
49       ComponentValidator componentValidator,
50       ComponentValidator subcomponentValidator,
51       BuilderValidator componentBuilderValidator,
52       BuilderValidator subcomponentBuilderValidator,
53       ComponentHierarchyValidator componentHierarchyValidator,
54       BindingGraphValidator bindingGraphValidator,
55       Factory componentDescriptorFactory,
56       BindingGraph.Factory bindingGraphFactory,
57       ComponentGenerator componentGenerator) {
58     super(
59         Component.class,
60         messager,
61         componentHierarchyValidator,
62         bindingGraphValidator,
63         componentDescriptorFactory,
64         bindingGraphFactory,
65         componentGenerator);
66     this.messager = messager;
67     this.componentValidator = componentValidator;
68     this.subcomponentValidator = subcomponentValidator;
69     this.componentBuilderValidator = componentBuilderValidator;
70     this.subcomponentBuilderValidator = subcomponentBuilderValidator;
71   }
72 
73   @Override
annotations()74   public Set<Class<? extends Annotation>> annotations() {
75     return ImmutableSet.<Class<? extends Annotation>>of(Component.class, Component.Builder.class,
76         Subcomponent.class, Subcomponent.Builder.class);
77   }
78 
79   @Override
componentElementValidator( SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation)80   protected ComponentElementValidator componentElementValidator(
81       SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
82     final Map<Element, ValidationReport<TypeElement>> builderReportsByComponent =
83         processComponentBuilders(elementsByAnnotation.get(Component.Builder.class));
84     final Set<Element> subcomponentBuilderElements =
85         elementsByAnnotation.get(Subcomponent.Builder.class);
86     final Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent =
87         processSubcomponentBuilders(subcomponentBuilderElements);
88     final Set<Element> subcomponentElements = elementsByAnnotation.get(Subcomponent.class);
89     final Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent =
90         processSubcomponents(subcomponentElements, subcomponentBuilderElements);
91     return new ComponentElementValidator() {
92       @Override
93       boolean validateComponent(TypeElement componentTypeElement, Messager messager) {
94         ComponentValidationReport validationReport =
95             componentValidator.validate(
96                 componentTypeElement, subcomponentElements, subcomponentBuilderElements);
97         validationReport.report().printMessagesTo(messager);
98         return isClean(
99             validationReport,
100             builderReportsByComponent,
101             reportsBySubcomponent,
102             builderReportsBySubcomponent);
103       }
104     };
105   }
106 
107   private Map<Element, ValidationReport<TypeElement>> processComponentBuilders(
108       Set<? extends Element> componentBuilderElements) {
109     Map<Element, ValidationReport<TypeElement>> builderReportsByComponent = Maps.newHashMap();
110     for (Element element : componentBuilderElements) {
111       ValidationReport<TypeElement> report =
112           componentBuilderValidator.validate(MoreElements.asType(element));
113       report.printMessagesTo(messager);
114       builderReportsByComponent.put(element.getEnclosingElement(), report);
115     }
116     return builderReportsByComponent;
117   }
118 
119   private Map<Element, ValidationReport<TypeElement>> processSubcomponentBuilders(
120       Set<? extends Element> subcomponentBuilderElements) {
121     Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent = Maps.newHashMap();
122     for (Element element : subcomponentBuilderElements) {
123       ValidationReport<TypeElement> report =
124           subcomponentBuilderValidator.validate(MoreElements.asType(element));
125       report.printMessagesTo(messager);
126       builderReportsBySubcomponent.put(element, report);
127     }
128     return builderReportsBySubcomponent;
129   }
130 
131   private Map<Element, ValidationReport<TypeElement>> processSubcomponents(
132       Set<? extends Element> subcomponentElements,
133       Set<? extends Element> subcomponentBuilderElements) {
134     Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent = Maps.newHashMap();
135     for (Element element : subcomponentElements) {
136       ComponentValidationReport report = subcomponentValidator.validate(
137           MoreElements.asType(element), subcomponentElements, subcomponentBuilderElements);
138       report.report().printMessagesTo(messager);
139       reportsBySubcomponent.put(element, report.report());
140     }
141     return reportsBySubcomponent;
142   }
143 
144   /**
145    * Returns true if the component's report is clean, its builder report is clean, and all
146    * referenced subcomponent reports & subcomponent builder reports are clean.
147    */
148   private boolean isClean(ComponentValidationReport report,
149       Map<Element, ValidationReport<TypeElement>> builderReportsByComponent,
150       Map<Element, ValidationReport<TypeElement>> reportsBySubcomponent,
151       Map<Element, ValidationReport<TypeElement>> builderReportsBySubcomponent) {
152     Element component = report.report().subject();
153     ValidationReport<?> componentReport = report.report();
154     if (!componentReport.isClean()) {
155       return false;
156     }
157     ValidationReport<?> builderReport = builderReportsByComponent.get(component);
158     if (builderReport != null && !builderReport.isClean()) {
159       return false;
160     }
161     for (Element element : report.referencedSubcomponents()) {
162       ValidationReport<?> subcomponentBuilderReport = builderReportsBySubcomponent.get(element);
163       if (subcomponentBuilderReport != null && !subcomponentBuilderReport.isClean()) {
164         return false;
165       }
166       ValidationReport<?> subcomponentReport = reportsBySubcomponent.get(element);
167       if (subcomponentReport != null && !subcomponentReport.isClean()) {
168         return false;
169       }
170     }
171     return true;
172   }
173 }
174