/* * Copyright (C) 2021 The Dagger Authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dagger.internal.codegen.validation; import static androidx.room.compiler.processing.compat.XConverters.toJavac; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static javax.tools.Diagnostic.Kind.ERROR; import androidx.room.compiler.processing.XFiler; import androidx.room.compiler.processing.XProcessingEnv; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import dagger.internal.codegen.compileroption.ProcessingOptions; import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl; import dagger.spi.DiagnosticReporter; import dagger.spi.model.BindingGraph; import dagger.spi.model.BindingGraphPlugin; import java.util.Map; import java.util.Set; import java.util.stream.Stream; import javax.inject.Inject; /** Initializes {@link BindingGraphPlugin}s. */ public final class ExternalBindingGraphPlugins { private final ImmutableSet legacyPlugins; private final ImmutableSet plugins; private final DiagnosticReporterFactory diagnosticReporterFactory; private final XFiler filer; private final XProcessingEnv processingEnv; private final Map processingOptions; @Inject ExternalBindingGraphPlugins( @External ImmutableSet legacyPlugins, @External ImmutableSet plugins, DiagnosticReporterFactory diagnosticReporterFactory, XFiler filer, XProcessingEnv processingEnv, @ProcessingOptions Map processingOptions) { this.legacyPlugins = legacyPlugins; this.plugins = plugins; this.diagnosticReporterFactory = diagnosticReporterFactory; this.filer = filer; this.processingEnv = processingEnv; this.processingOptions = processingOptions; } /** Returns {@link BindingGraphPlugin#supportedOptions()} from all the plugins. */ public ImmutableSet allSupportedOptions() { return Stream.concat( legacyPlugins.stream().flatMap(plugin -> plugin.supportedOptions().stream()), plugins.stream().flatMap(plugin -> plugin.supportedOptions().stream())) .collect(toImmutableSet()); } /** Initializes the plugins. */ // TODO(ronshapiro): Should we validate the uniqueness of plugin names? public void initializePlugins() { plugins.forEach(this::initializePlugin); legacyPlugins.forEach(this::initializeLegacyPlugin); } private void initializePlugin(BindingGraphPlugin plugin) { Set supportedOptions = plugin.supportedOptions(); Map filteredOptions = supportedOptions.isEmpty() ? ImmutableMap.of() : Maps.filterKeys(processingOptions, supportedOptions::contains); plugin.init(SpiModelBindingGraphConverter.toSpiModel(processingEnv), filteredOptions); } public void onProcessingRoundBegin() { plugins.forEach(BindingGraphPlugin::onProcessingRoundBegin); } private void initializeLegacyPlugin(dagger.spi.BindingGraphPlugin plugin) { plugin.initFiler(toJavac(filer)); plugin.initTypes(toJavac(processingEnv).getTypeUtils()); // ALLOW_TYPES_ELEMENTS plugin.initElements(toJavac(processingEnv).getElementUtils()); // ALLOW_TYPES_ELEMENTS Set supportedOptions = plugin.supportedOptions(); if (!supportedOptions.isEmpty()) { plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains)); } } /** Returns {@code false} if any of the plugins reported an error. */ boolean visit(dagger.internal.codegen.model.BindingGraph graph) { return visitLegacyPlugins(graph) && visitPlugins(graph); } private boolean visitLegacyPlugins(dagger.internal.codegen.model.BindingGraph graph) { // Return early to avoid converting the binding graph when there are no external plugins. if (legacyPlugins.isEmpty()) { return true; } dagger.model.BindingGraph legacyGraph = ModelBindingGraphConverter.toModel(graph); boolean isClean = true; for (dagger.spi.BindingGraphPlugin legacyPlugin : legacyPlugins) { DiagnosticReporterImpl reporter = diagnosticReporterFactory.reporter(graph, legacyPlugin.pluginName()); DiagnosticReporter legacyReporter = ModelBindingGraphConverter.toModel(reporter); legacyPlugin.visitGraph(legacyGraph, legacyReporter); if (reporter.reportedDiagnosticKinds().contains(ERROR)) { isClean = false; } } return isClean; } private boolean visitPlugins(dagger.internal.codegen.model.BindingGraph graph) { BindingGraph spiGraph = SpiModelBindingGraphConverter.toSpiModel(graph, processingEnv); boolean isClean = true; for (BindingGraphPlugin plugin : plugins) { DiagnosticReporterImpl reporter = diagnosticReporterFactory.reporter(graph, plugin.pluginName()); plugin.visitGraph(spiGraph, SpiModelBindingGraphConverter.toSpiModel(reporter)); if (reporter.reportedDiagnosticKinds().contains(ERROR)) { isClean = false; } } return isClean; } public void endPlugins() { legacyPlugins.forEach(dagger.spi.BindingGraphPlugin::onPluginEnd); plugins.forEach(BindingGraphPlugin::onPluginEnd); } }