1 /*
2  * Copyright (C) 2018 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.validation;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static javax.tools.Diagnostic.Kind.ERROR;
21 
22 import com.google.common.collect.ImmutableSet;
23 import dagger.internal.codegen.compileroption.CompilerOptions;
24 import dagger.internal.codegen.compileroption.ValidationType;
25 import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
26 import dagger.model.BindingGraph;
27 import dagger.spi.BindingGraphPlugin;
28 import javax.inject.Inject;
29 import javax.inject.Singleton;
30 import javax.lang.model.element.TypeElement;
31 
32 /** Validates a {@link BindingGraph}. */
33 @Singleton
34 public final class BindingGraphValidator {
35   private final ImmutableSet<BindingGraphPlugin> validationPlugins;
36   private final ImmutableSet<BindingGraphPlugin> externalPlugins;
37   private final DiagnosticReporterFactory diagnosticReporterFactory;
38   private final CompilerOptions compilerOptions;
39 
40   @Inject
BindingGraphValidator( @alidation ImmutableSet<BindingGraphPlugin> validationPlugins, ImmutableSet<BindingGraphPlugin> externalPlugins, DiagnosticReporterFactory diagnosticReporterFactory, CompilerOptions compilerOptions)41   BindingGraphValidator(
42       @Validation ImmutableSet<BindingGraphPlugin> validationPlugins,
43       ImmutableSet<BindingGraphPlugin> externalPlugins,
44       DiagnosticReporterFactory diagnosticReporterFactory,
45       CompilerOptions compilerOptions) {
46     this.validationPlugins = validationPlugins;
47     this.externalPlugins = externalPlugins;
48     this.diagnosticReporterFactory = checkNotNull(diagnosticReporterFactory);
49     this.compilerOptions = compilerOptions;
50   }
51 
52   /** Returns {@code true} if validation or analysis is required on the full binding graph. */
shouldDoFullBindingGraphValidation(TypeElement component)53   public boolean shouldDoFullBindingGraphValidation(TypeElement component) {
54     return requiresFullBindingGraphValidation()
55         || compilerOptions.pluginsVisitFullBindingGraphs(component);
56   }
57 
requiresFullBindingGraphValidation()58   private boolean requiresFullBindingGraphValidation() {
59     return !compilerOptions.fullBindingGraphValidationType().equals(ValidationType.NONE);
60   }
61 
62   /** Returns {@code true} if no errors are reported for {@code graph}. */
isValid(BindingGraph graph)63   public boolean isValid(BindingGraph graph) {
64     return validate(graph) && visitPlugins(graph);
65   }
66 
67   /** Returns {@code true} if validation plugins report no errors. */
validate(BindingGraph graph)68   private boolean validate(BindingGraph graph) {
69     if (graph.isFullBindingGraph() && !requiresFullBindingGraphValidation()) {
70       return true;
71     }
72 
73     boolean errorsAsWarnings =
74         graph.isFullBindingGraph()
75         && compilerOptions.fullBindingGraphValidationType().equals(ValidationType.WARNING);
76 
77     return runPlugins(validationPlugins, graph, errorsAsWarnings);
78   }
79 
80   /** Returns {@code true} if external plugins report no errors. */
visitPlugins(BindingGraph graph)81   private boolean visitPlugins(BindingGraph graph) {
82     TypeElement component = graph.rootComponentNode().componentPath().currentComponent();
83     if (graph.isFullBindingGraph()
84         // TODO(b/135938915): Consider not visiting plugins if only
85         // fullBindingGraphValidation is enabled.
86         && !requiresFullBindingGraphValidation()
87         && !compilerOptions.pluginsVisitFullBindingGraphs(component)) {
88       return true;
89     }
90     return runPlugins(externalPlugins, graph, /*errorsAsWarnings=*/ false);
91   }
92 
93   /** Returns {@code false} if any of the plugins reported an error. */
runPlugins( ImmutableSet<BindingGraphPlugin> plugins, BindingGraph graph, boolean errorsAsWarnings)94   private boolean runPlugins(
95       ImmutableSet<BindingGraphPlugin> plugins, BindingGraph graph, boolean errorsAsWarnings) {
96     boolean isClean = true;
97     for (BindingGraphPlugin plugin : plugins) {
98       DiagnosticReporterImpl reporter =
99           diagnosticReporterFactory.reporter(graph, plugin, errorsAsWarnings);
100       plugin.visitGraph(graph, reporter);
101       if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
102         isClean = false;
103       }
104     }
105     return isClean;
106   }
107 }
108