• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 androidx.room.compiler.processing.compat.XConverters.toJavac;
20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
21 import static javax.tools.Diagnostic.Kind.ERROR;
22 
23 import androidx.room.compiler.processing.XFiler;
24 import androidx.room.compiler.processing.XProcessingEnv;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.Maps;
28 import dagger.internal.codegen.compileroption.ProcessingOptions;
29 import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
30 import dagger.spi.DiagnosticReporter;
31 import dagger.spi.model.BindingGraph;
32 import dagger.spi.model.BindingGraphPlugin;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.stream.Stream;
36 import javax.inject.Inject;
37 
38 /** Initializes {@link BindingGraphPlugin}s. */
39 public final class ExternalBindingGraphPlugins {
40   private final ImmutableSet<dagger.spi.BindingGraphPlugin> legacyPlugins;
41   private final ImmutableSet<BindingGraphPlugin> plugins;
42   private final DiagnosticReporterFactory diagnosticReporterFactory;
43   private final XFiler filer;
44   private final XProcessingEnv processingEnv;
45   private final Map<String, String> processingOptions;
46 
47   @Inject
ExternalBindingGraphPlugins( @xternal ImmutableSet<dagger.spi.BindingGraphPlugin> legacyPlugins, @External ImmutableSet<BindingGraphPlugin> plugins, DiagnosticReporterFactory diagnosticReporterFactory, XFiler filer, XProcessingEnv processingEnv, @ProcessingOptions Map<String, String> processingOptions)48   ExternalBindingGraphPlugins(
49       @External ImmutableSet<dagger.spi.BindingGraphPlugin> legacyPlugins,
50       @External ImmutableSet<BindingGraphPlugin> plugins,
51       DiagnosticReporterFactory diagnosticReporterFactory,
52       XFiler filer,
53       XProcessingEnv processingEnv,
54       @ProcessingOptions Map<String, String> processingOptions) {
55     this.legacyPlugins = legacyPlugins;
56     this.plugins = plugins;
57     this.diagnosticReporterFactory = diagnosticReporterFactory;
58     this.filer = filer;
59     this.processingEnv = processingEnv;
60     this.processingOptions = processingOptions;
61   }
62 
63   /** Returns {@link BindingGraphPlugin#supportedOptions()} from all the plugins. */
allSupportedOptions()64   public ImmutableSet<String> allSupportedOptions() {
65     return Stream.concat(
66             legacyPlugins.stream().flatMap(plugin -> plugin.supportedOptions().stream()),
67             plugins.stream().flatMap(plugin -> plugin.supportedOptions().stream()))
68         .collect(toImmutableSet());
69   }
70 
71   /** Initializes the plugins. */
72   // TODO(ronshapiro): Should we validate the uniqueness of plugin names?
initializePlugins()73   public void initializePlugins() {
74     plugins.forEach(this::initializePlugin);
75     legacyPlugins.forEach(this::initializeLegacyPlugin);
76   }
77 
initializePlugin(BindingGraphPlugin plugin)78   private void initializePlugin(BindingGraphPlugin plugin) {
79     Set<String> supportedOptions = plugin.supportedOptions();
80     Map<String, String> filteredOptions =
81         supportedOptions.isEmpty()
82             ? ImmutableMap.of()
83             : Maps.filterKeys(processingOptions, supportedOptions::contains);
84     plugin.init(SpiModelBindingGraphConverter.toSpiModel(processingEnv), filteredOptions);
85   }
86 
initializeLegacyPlugin(dagger.spi.BindingGraphPlugin plugin)87   private void initializeLegacyPlugin(dagger.spi.BindingGraphPlugin plugin) {
88     plugin.initFiler(toJavac(filer));
89     plugin.initTypes(toJavac(processingEnv).getTypeUtils()); // ALLOW_TYPES_ELEMENTS
90     plugin.initElements(toJavac(processingEnv).getElementUtils()); // ALLOW_TYPES_ELEMENTS
91     Set<String> supportedOptions = plugin.supportedOptions();
92     if (!supportedOptions.isEmpty()) {
93       plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains));
94     }
95   }
96 
97   /** Returns {@code false} if any of the plugins reported an error. */
visit(dagger.internal.codegen.model.BindingGraph graph)98   boolean visit(dagger.internal.codegen.model.BindingGraph graph) {
99     return visitLegacyPlugins(graph) && visitPlugins(graph);
100   }
101 
visitLegacyPlugins(dagger.internal.codegen.model.BindingGraph graph)102   private boolean visitLegacyPlugins(dagger.internal.codegen.model.BindingGraph graph) {
103     // Return early to avoid converting the binding graph when there are no external plugins.
104     if (legacyPlugins.isEmpty()) {
105       return true;
106     }
107     dagger.model.BindingGraph legacyGraph = ModelBindingGraphConverter.toModel(graph);
108     boolean isClean = true;
109     for (dagger.spi.BindingGraphPlugin legacyPlugin : legacyPlugins) {
110       DiagnosticReporterImpl reporter =
111           diagnosticReporterFactory.reporter(graph, legacyPlugin.pluginName());
112       DiagnosticReporter legacyReporter = ModelBindingGraphConverter.toModel(reporter);
113       legacyPlugin.visitGraph(legacyGraph, legacyReporter);
114       if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
115         isClean = false;
116       }
117     }
118     return isClean;
119   }
120 
visitPlugins(dagger.internal.codegen.model.BindingGraph graph)121   private boolean visitPlugins(dagger.internal.codegen.model.BindingGraph graph) {
122     BindingGraph spiGraph = SpiModelBindingGraphConverter.toSpiModel(graph, processingEnv);
123     boolean isClean = true;
124     for (BindingGraphPlugin plugin : plugins) {
125       DiagnosticReporterImpl reporter =
126           diagnosticReporterFactory.reporter(graph, plugin.pluginName());
127       plugin.visitGraph(spiGraph, SpiModelBindingGraphConverter.toSpiModel(reporter));
128       if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
129         isClean = false;
130       }
131     }
132     return isClean;
133   }
134 
endPlugins()135   public void endPlugins() {
136     legacyPlugins.forEach(dagger.spi.BindingGraphPlugin::onPluginEnd);
137     plugins.forEach(BindingGraphPlugin::onPluginEnd);
138   }
139 }
140