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