| /* |
| * Copyright (C) 2018 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.bindinggraphvalidation; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static com.google.common.base.Verify.verify; |
| import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding; |
| import static dagger.internal.codegen.extension.DaggerStreams.instancesOf; |
| import static javax.tools.Diagnostic.Kind.ERROR; |
| |
| import dagger.internal.codegen.validation.ValidationBindingGraphPlugin; |
| import dagger.spi.model.Binding; |
| import dagger.spi.model.BindingGraph; |
| import dagger.spi.model.BindingGraph.DependencyEdge; |
| import dagger.spi.model.BindingGraph.Node; |
| import dagger.spi.model.DiagnosticReporter; |
| import java.util.stream.Stream; |
| import javax.inject.Inject; |
| |
| /** |
| * Reports an error for each provision-only dependency request that is satisfied by a production |
| * binding. |
| */ |
| // TODO(b/29509141): Clarify the error. |
| final class ProvisionDependencyOnProducerBindingValidator extends ValidationBindingGraphPlugin { |
| |
| @Inject |
| ProvisionDependencyOnProducerBindingValidator() {} |
| |
| @Override |
| public String pluginName() { |
| return "Dagger/ProviderDependsOnProducer"; |
| } |
| |
| @Override |
| public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) { |
| provisionDependenciesOnProductionBindings(bindingGraph) |
| .forEach( |
| provisionDependent -> |
| diagnosticReporter.reportDependency( |
| ERROR, |
| provisionDependent, |
| provisionDependent.isEntryPoint() |
| ? entryPointErrorMessage(provisionDependent) |
| : dependencyErrorMessage(provisionDependent, bindingGraph))); |
| } |
| |
| private Stream<DependencyEdge> provisionDependenciesOnProductionBindings( |
| BindingGraph bindingGraph) { |
| return bindingGraph.bindings().stream() |
| .filter(binding -> binding.isProduction()) |
| .flatMap(binding -> incomingDependencies(binding, bindingGraph)) |
| .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph)); |
| } |
| |
| /** Returns the dependencies on {@code binding}. */ |
| // TODO(dpb): Move to BindingGraph. |
| private Stream<DependencyEdge> incomingDependencies(Binding binding, BindingGraph bindingGraph) { |
| return bindingGraph.network().inEdges(binding).stream() |
| .flatMap(instancesOf(DependencyEdge.class)); |
| } |
| |
| // TODO(ronshapiro): merge with MissingBindingValidator.dependencyCanUseProduction |
| private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) { |
| return edge.isEntryPoint() |
| ? canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind()) |
| : bindingRequestingDependency(edge, bindingGraph).isProduction(); |
| } |
| |
| /** |
| * Returns the binding that requests a dependency. |
| * |
| * @throws IllegalArgumentException if {@code dependency} is an {@linkplain |
| * DependencyEdge#isEntryPoint() entry point}. |
| */ |
| // TODO(dpb): Move to BindingGraph. |
| private Binding bindingRequestingDependency( |
| DependencyEdge dependency, BindingGraph bindingGraph) { |
| checkArgument(!dependency.isEntryPoint()); |
| Node source = bindingGraph.network().incidentNodes(dependency).source(); |
| verify( |
| source instanceof Binding, |
| "expected source of %s to be a binding, but was: %s", |
| dependency, |
| source); |
| return (Binding) source; |
| } |
| |
| private String entryPointErrorMessage(DependencyEdge entryPoint) { |
| return String.format( |
| "%s is a provision entry-point, which cannot depend on a production.", |
| entryPoint.dependencyRequest().key()); |
| } |
| |
| private String dependencyErrorMessage( |
| DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) { |
| return String.format( |
| "%s is a provision, which cannot depend on a production.", |
| bindingRequestingDependency(dependencyOnProduction, bindingGraph).key()); |
| } |
| } |