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