• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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