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