• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.bindinggraphvalidation;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Verify.verify;
21 import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
22 import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
23 import static javax.tools.Diagnostic.Kind.ERROR;
24 
25 import dagger.internal.codegen.model.Binding;
26 import dagger.internal.codegen.model.BindingGraph;
27 import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
28 import dagger.internal.codegen.model.BindingGraph.Node;
29 import dagger.internal.codegen.model.DiagnosticReporter;
30 import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
31 import java.util.stream.Stream;
32 import javax.inject.Inject;
33 
34 /**
35  * Reports an error for each provision-only dependency request that is satisfied by a production
36  * binding.
37  */
38 // TODO(b/29509141): Clarify the error.
39 final class ProvisionDependencyOnProducerBindingValidator extends ValidationBindingGraphPlugin {
40 
41   @Inject
ProvisionDependencyOnProducerBindingValidator()42   ProvisionDependencyOnProducerBindingValidator() {}
43 
44   @Override
pluginName()45   public String pluginName() {
46     return "Dagger/ProviderDependsOnProducer";
47   }
48 
49   @Override
visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter)50   public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
51     provisionDependenciesOnProductionBindings(bindingGraph)
52         .forEach(
53             provisionDependent ->
54                 diagnosticReporter.reportDependency(
55                     ERROR,
56                     provisionDependent,
57                     provisionDependent.isEntryPoint()
58                         ? entryPointErrorMessage(provisionDependent)
59                         : dependencyErrorMessage(provisionDependent, bindingGraph)));
60   }
61 
provisionDependenciesOnProductionBindings( BindingGraph bindingGraph)62   private Stream<DependencyEdge> provisionDependenciesOnProductionBindings(
63       BindingGraph bindingGraph) {
64     return bindingGraph.bindings().stream()
65         .filter(binding -> binding.isProduction())
66         .flatMap(binding -> incomingDependencies(binding, bindingGraph))
67         .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph));
68   }
69 
70   /** Returns the dependencies on {@code binding}. */
71   // TODO(dpb): Move to BindingGraph.
incomingDependencies(Binding binding, BindingGraph bindingGraph)72   private Stream<DependencyEdge> incomingDependencies(Binding binding, BindingGraph bindingGraph) {
73     return bindingGraph.network().inEdges(binding).stream()
74         .flatMap(instancesOf(DependencyEdge.class));
75   }
76 
77   // TODO(ronshapiro): merge with MissingBindingValidator.dependencyCanUseProduction
dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph)78   private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) {
79     return edge.isEntryPoint()
80         ? canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind())
81         : bindingRequestingDependency(edge, bindingGraph).isProduction();
82   }
83 
84   /**
85    * Returns the binding that requests a dependency.
86    *
87    * @throws IllegalArgumentException if {@code dependency} is an {@linkplain
88    *     DependencyEdge#isEntryPoint() entry point}.
89    */
90   // TODO(dpb): Move to BindingGraph.
bindingRequestingDependency( DependencyEdge dependency, BindingGraph bindingGraph)91   private Binding bindingRequestingDependency(
92       DependencyEdge dependency, BindingGraph bindingGraph) {
93     checkArgument(!dependency.isEntryPoint());
94     Node source = bindingGraph.network().incidentNodes(dependency).source();
95     verify(
96         source instanceof Binding,
97         "expected source of %s to be a binding, but was: %s",
98         dependency,
99         source);
100     return (Binding) source;
101   }
102 
entryPointErrorMessage(DependencyEdge entryPoint)103   private String entryPointErrorMessage(DependencyEdge entryPoint) {
104     return String.format(
105         "%s is a provision entry-point, which cannot depend on a production.",
106         entryPoint.dependencyRequest().key());
107   }
108 
dependencyErrorMessage( DependencyEdge dependencyOnProduction, BindingGraph bindingGraph)109   private String dependencyErrorMessage(
110       DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) {
111     return String.format(
112         "%s is a provision, which cannot depend on a production.",
113         bindingRequestingDependency(dependencyOnProduction, bindingGraph).key());
114   }
115 }
116