1 /* 2 * Copyright (C) 2017 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.rootComponentAnnotations; 21 import static dagger.internal.codegen.base.ComponentCreatorAnnotation.rootComponentCreatorAnnotations; 22 import static java.util.Collections.disjoint; 23 24 import androidx.room.compiler.processing.XMessager; 25 import androidx.room.compiler.processing.XTypeElement; 26 import com.google.common.collect.ImmutableSet; 27 import com.squareup.javapoet.ClassName; 28 import dagger.internal.codegen.base.SourceFileGenerator; 29 import dagger.internal.codegen.binding.BindingGraph; 30 import dagger.internal.codegen.binding.ComponentDescriptor; 31 import dagger.internal.codegen.validation.ComponentCreatorValidator; 32 import dagger.internal.codegen.validation.ComponentValidator; 33 import dagger.internal.codegen.validation.ValidationReport; 34 import java.util.Set; 35 import javax.inject.Inject; 36 37 /** 38 * A processing step that emits the API of a generated component, without any actual implementation. 39 * 40 * <p>When compiling a header jar (hjar), Bazel needs to run annotation processors that generate 41 * API, like Dagger, to see what code they might output. Full {@link BindingGraph} analysis is 42 * costly and unnecessary from the perspective of the header compiler; it's sole goal is to pass 43 * along a slimmed down version of what will be the jar for a particular compilation, whether or not 44 * that compilation succeeds. If it does not, the compilation pipeline will fail, even if header 45 * compilation succeeded. 46 * 47 * <p>The components emitted by this processing step include all of the API elements exposed by the 48 * normal step. Method bodies are omitted as Turbine ignores them entirely. 49 */ 50 final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<XTypeElement> { 51 private final XMessager messager; 52 private final ComponentValidator componentValidator; 53 private final ComponentCreatorValidator creatorValidator; 54 private final ComponentDescriptor.Factory componentDescriptorFactory; 55 private final SourceFileGenerator<ComponentDescriptor> componentGenerator; 56 57 @Inject ComponentHjarProcessingStep( XMessager messager, ComponentValidator componentValidator, ComponentCreatorValidator creatorValidator, ComponentDescriptor.Factory componentDescriptorFactory, SourceFileGenerator<ComponentDescriptor> componentGenerator)58 ComponentHjarProcessingStep( 59 XMessager messager, 60 ComponentValidator componentValidator, 61 ComponentCreatorValidator creatorValidator, 62 ComponentDescriptor.Factory componentDescriptorFactory, 63 SourceFileGenerator<ComponentDescriptor> componentGenerator) { 64 this.messager = messager; 65 this.componentValidator = componentValidator; 66 this.creatorValidator = creatorValidator; 67 this.componentDescriptorFactory = componentDescriptorFactory; 68 this.componentGenerator = componentGenerator; 69 } 70 71 @Override annotationClassNames()72 public Set<ClassName> annotationClassNames() { 73 return union(rootComponentAnnotations(), rootComponentCreatorAnnotations()); 74 } 75 76 // TODO(ronshapiro): Validation might not even be necessary. We should measure it and figure out 77 // if it's worth seeing if removing it will still work. We could potentially add a new catch 78 // clause for any exception that's not TypeNotPresentException and ignore the component entirely 79 // in that case. 80 @Override process(XTypeElement element, ImmutableSet<ClassName> annotations)81 protected void process(XTypeElement element, ImmutableSet<ClassName> annotations) { 82 if (!disjoint(annotations, rootComponentAnnotations())) { 83 processRootComponent(element); 84 } 85 if (!disjoint(annotations, rootComponentCreatorAnnotations())) { 86 processRootCreator(element); 87 } 88 } 89 processRootComponent(XTypeElement element)90 private void processRootComponent(XTypeElement element) { 91 ValidationReport validationReport = componentValidator.validate(element); 92 validationReport.printMessagesTo(messager); 93 if (validationReport.isClean()) { 94 componentGenerator.generate( 95 componentDescriptorFactory.rootComponentDescriptor(element), messager); 96 } 97 } 98 processRootCreator(XTypeElement creator)99 private void processRootCreator(XTypeElement creator) { 100 creatorValidator.validate(creator).printMessagesTo(messager); 101 } 102 } 103