1 /* 2 * Copyright (C) 2014 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.processingstep; 18 19 import static com.google.common.collect.Sets.union; 20 import static dagger.internal.codegen.base.ComponentAnnotation.allComponentAnnotations; 21 import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotations; 22 import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations; 23 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.allCreatorAnnotations; 24 import static java.util.Collections.disjoint; 25 26 import androidx.room.compiler.processing.XMessager; 27 import androidx.room.compiler.processing.XTypeElement; 28 import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; 29 import com.google.common.base.Supplier; 30 import com.google.common.base.Suppliers; 31 import com.google.common.collect.ImmutableSet; 32 import com.squareup.javapoet.ClassName; 33 import dagger.internal.codegen.base.SourceFileGenerator; 34 import dagger.internal.codegen.binding.BindingGraph; 35 import dagger.internal.codegen.binding.BindingGraphFactory; 36 import dagger.internal.codegen.binding.ComponentDescriptor; 37 import dagger.internal.codegen.validation.BindingGraphValidator; 38 import dagger.internal.codegen.validation.ComponentCreatorValidator; 39 import dagger.internal.codegen.validation.ComponentDescriptorValidator; 40 import dagger.internal.codegen.validation.ComponentValidator; 41 import dagger.internal.codegen.validation.ValidationReport; 42 import java.util.Set; 43 import javax.inject.Inject; 44 45 /** 46 * A {@link ProcessingStep} that is responsible for dealing with a component or production component 47 * as part of the {@link ComponentProcessor}. 48 */ 49 final class ComponentProcessingStep extends TypeCheckingProcessingStep<XTypeElement> { 50 private final XMessager messager; 51 private final ComponentValidator componentValidator; 52 private final ComponentCreatorValidator creatorValidator; 53 private final ComponentDescriptorValidator componentDescriptorValidator; 54 private final ComponentDescriptor.Factory componentDescriptorFactory; 55 private final BindingGraphFactory bindingGraphFactory; 56 private final SourceFileGenerator<BindingGraph> componentGenerator; 57 private final BindingGraphValidator bindingGraphValidator; 58 59 @Inject ComponentProcessingStep( XMessager messager, ComponentValidator componentValidator, ComponentCreatorValidator creatorValidator, ComponentDescriptorValidator componentDescriptorValidator, ComponentDescriptor.Factory componentDescriptorFactory, BindingGraphFactory bindingGraphFactory, SourceFileGenerator<BindingGraph> componentGenerator, BindingGraphValidator bindingGraphValidator)60 ComponentProcessingStep( 61 XMessager messager, 62 ComponentValidator componentValidator, 63 ComponentCreatorValidator creatorValidator, 64 ComponentDescriptorValidator componentDescriptorValidator, 65 ComponentDescriptor.Factory componentDescriptorFactory, 66 BindingGraphFactory bindingGraphFactory, 67 SourceFileGenerator<BindingGraph> componentGenerator, 68 BindingGraphValidator bindingGraphValidator) { 69 this.messager = messager; 70 this.componentValidator = componentValidator; 71 this.creatorValidator = creatorValidator; 72 this.componentDescriptorValidator = componentDescriptorValidator; 73 this.componentDescriptorFactory = componentDescriptorFactory; 74 this.bindingGraphFactory = bindingGraphFactory; 75 this.componentGenerator = componentGenerator; 76 this.bindingGraphValidator = bindingGraphValidator; 77 } 78 79 @Override annotationClassNames()80 public Set<ClassName> annotationClassNames() { 81 return union(allComponentAnnotations(), allCreatorAnnotations()); 82 } 83 84 @Override process(XTypeElement element, ImmutableSet<ClassName> annotations)85 protected void process(XTypeElement element, ImmutableSet<ClassName> annotations) { 86 if (!disjoint(annotations, rootComponentAnnotations())) { 87 processRootComponent(element); 88 } 89 if (!disjoint(annotations, subcomponentAnnotations())) { 90 processSubcomponent(element); 91 } 92 if (!disjoint(annotations, allCreatorAnnotations())) { 93 processCreator(element); 94 } 95 } 96 processRootComponent(XTypeElement component)97 private void processRootComponent(XTypeElement component) { 98 if (!isComponentValid(component)) { 99 return; 100 } 101 ComponentDescriptor componentDescriptor = 102 componentDescriptorFactory.rootComponentDescriptor(component); 103 if (!isValid(componentDescriptor)) { 104 return; 105 } 106 107 Supplier<dagger.internal.codegen.model.BindingGraph> fullBindingGraphSupplier = 108 Suppliers.memoize( 109 () -> bindingGraphFactory.create(componentDescriptor, true).topLevelBindingGraph()); 110 if (bindingGraphValidator.shouldDoFullBindingGraphValidation(component)) { 111 if (!bindingGraphValidator.isValid(fullBindingGraphSupplier.get())) { 112 return; 113 } 114 } 115 116 BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor, false); 117 if (bindingGraphValidator.isValid( 118 bindingGraph.topLevelBindingGraph(), fullBindingGraphSupplier)) { 119 generateComponent(bindingGraph); 120 } 121 } 122 processSubcomponent(XTypeElement subcomponent)123 private void processSubcomponent(XTypeElement subcomponent) { 124 if (!isComponentValid(subcomponent)) { 125 return; 126 } 127 // TODO(dpb): ComponentDescriptorValidator for subcomponents, as we do for root components. 128 ComponentDescriptor subcomponentDescriptor = 129 componentDescriptorFactory.subcomponentDescriptor(subcomponent); 130 if (!bindingGraphValidator.shouldDoFullBindingGraphValidation(subcomponent)) { 131 return; 132 } 133 BindingGraph fullBindingGraph = bindingGraphFactory.create(subcomponentDescriptor, true); 134 // In this case, we don't actually care about the return value. The important part here is that 135 // BindingGraphValidator#isValid() runs all of the SPI plugins and reports any errors. 136 // TODO(bcorso): Add a separate API with no return value for this particular case. 137 boolean unusedIsValid = bindingGraphValidator.isValid(fullBindingGraph.topLevelBindingGraph()); 138 } 139 generateComponent(BindingGraph bindingGraph)140 private void generateComponent(BindingGraph bindingGraph) { 141 componentGenerator.generate(bindingGraph, messager); 142 } 143 processCreator(XTypeElement creator)144 private void processCreator(XTypeElement creator) { 145 creatorValidator.validate(creator).printMessagesTo(messager); 146 } 147 isComponentValid(XTypeElement component)148 private boolean isComponentValid(XTypeElement component) { 149 ValidationReport report = componentValidator.validate(component); 150 report.printMessagesTo(messager); 151 return report.isClean(); 152 } 153 isValid(ComponentDescriptor componentDescriptor)154 private boolean isValid(ComponentDescriptor componentDescriptor) { 155 ValidationReport componentDescriptorReport = 156 componentDescriptorValidator.validate(componentDescriptor); 157 componentDescriptorReport.printMessagesTo(messager); 158 return componentDescriptorReport.isClean(); 159 } 160 } 161