• 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 dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
22 
23 import com.google.auto.value.AutoValue;
24 import com.google.auto.value.extension.memoized.Memoized;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSetMultimap;
27 import com.google.common.graph.EndpointPair;
28 import com.google.common.graph.ImmutableNetwork;
29 import com.google.common.graph.MutableNetwork;
30 import com.google.common.graph.Network;
31 import com.google.common.graph.NetworkBuilder;
32 import com.google.errorprone.annotations.FormatMethod;
33 import dagger.internal.codegen.model.DaggerAnnotation;
34 import dagger.internal.codegen.model.DaggerElement;
35 import dagger.internal.codegen.model.DaggerTypeElement;
36 import dagger.internal.codegen.xprocessing.XElements;
37 import dagger.model.Binding;
38 import dagger.model.BindingGraph;
39 import dagger.model.BindingGraph.ChildFactoryMethodEdge;
40 import dagger.model.BindingGraph.ComponentNode;
41 import dagger.model.BindingGraph.DependencyEdge;
42 import dagger.model.BindingGraph.Edge;
43 import dagger.model.BindingGraph.MaybeBinding;
44 import dagger.model.BindingGraph.MissingBinding;
45 import dagger.model.BindingGraph.Node;
46 import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
47 import dagger.model.BindingKind;
48 import dagger.model.ComponentPath;
49 import dagger.model.DependencyRequest;
50 import dagger.model.Key;
51 import dagger.model.Key.MultibindingContributionIdentifier;
52 import dagger.model.RequestKind;
53 import dagger.model.Scope;
54 import dagger.spi.DiagnosticReporter;
55 import java.util.Optional;
56 import javax.tools.Diagnostic;
57 
58 /** A Utility class for converting to the {@link BindingGraph} used by external plugins. */
59 public final class ModelBindingGraphConverter {
ModelBindingGraphConverter()60   private ModelBindingGraphConverter() {}
61 
62   /** Returns a {@link DiagnosticReporter} from a {@link dagger.spi.DiagnosticReporter}. */
toModel( dagger.internal.codegen.model.DiagnosticReporter reporter)63   public static DiagnosticReporter toModel(
64       dagger.internal.codegen.model.DiagnosticReporter reporter) {
65     return DiagnosticReporterImpl.create(reporter);
66   }
67 
68   /** Returns a {@link BindingGraph} from a {@link dagger.internal.codegen.model.BindingGraph}. */
toModel(dagger.internal.codegen.model.BindingGraph graph)69   public static BindingGraph toModel(dagger.internal.codegen.model.BindingGraph graph) {
70     return BindingGraphImpl.create(graph);
71   }
72 
toModel( Network< dagger.internal.codegen.model.BindingGraph.Node, dagger.internal.codegen.model.BindingGraph.Edge> internalNetwork)73   private static ImmutableNetwork<Node, Edge> toModel(
74       Network<
75               dagger.internal.codegen.model.BindingGraph.Node,
76               dagger.internal.codegen.model.BindingGraph.Edge>
77           internalNetwork) {
78     MutableNetwork<Node, Edge> network =
79         NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
80 
81     ImmutableMap<dagger.internal.codegen.model.BindingGraph.Node, Node> fromInternalNodes =
82         internalNetwork.nodes().stream()
83             .collect(toImmutableMap(node -> node, ModelBindingGraphConverter::toModel));
84 
85     for (Node node : fromInternalNodes.values()) {
86       network.addNode(node);
87     }
88     for (dagger.internal.codegen.model.BindingGraph.Edge edge : internalNetwork.edges()) {
89       EndpointPair<dagger.internal.codegen.model.BindingGraph.Node> edgePair =
90           internalNetwork.incidentNodes(edge);
91       network.addEdge(
92           fromInternalNodes.get(edgePair.source()),
93           fromInternalNodes.get(edgePair.target()),
94           toModel(edge));
95     }
96     return ImmutableNetwork.copyOf(network);
97   }
98 
toModel(dagger.internal.codegen.model.BindingGraph.Node node)99   private static Node toModel(dagger.internal.codegen.model.BindingGraph.Node node) {
100     if (node instanceof dagger.internal.codegen.model.Binding) {
101       return BindingNodeImpl.create((dagger.internal.codegen.model.Binding) node);
102     } else if (node instanceof dagger.internal.codegen.model.BindingGraph.ComponentNode) {
103       return ComponentNodeImpl.create(
104           (dagger.internal.codegen.model.BindingGraph.ComponentNode) node);
105     } else if (node instanceof dagger.internal.codegen.model.BindingGraph.MissingBinding) {
106       return MissingBindingImpl.create(
107           (dagger.internal.codegen.model.BindingGraph.MissingBinding) node);
108     } else {
109       throw new IllegalStateException("Unhandled node type: " + node.getClass());
110     }
111   }
112 
toModel(dagger.internal.codegen.model.BindingGraph.Edge edge)113   private static Edge toModel(dagger.internal.codegen.model.BindingGraph.Edge edge) {
114     if (edge instanceof dagger.internal.codegen.model.BindingGraph.DependencyEdge) {
115       return DependencyEdgeImpl.create(
116           (dagger.internal.codegen.model.BindingGraph.DependencyEdge) edge);
117     } else if (edge instanceof dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) {
118       return ChildFactoryMethodEdgeImpl.create(
119           (dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) edge);
120     } else if (edge
121         instanceof dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) {
122       return SubcomponentCreatorBindingEdgeImpl.create(
123           (dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) edge);
124     } else {
125       throw new IllegalStateException("Unhandled edge type: " + edge.getClass());
126     }
127   }
128 
toModel( dagger.internal.codegen.model.Key.MultibindingContributionIdentifier identifier)129   private static MultibindingContributionIdentifier toModel(
130       dagger.internal.codegen.model.Key.MultibindingContributionIdentifier identifier) {
131     return new MultibindingContributionIdentifier(
132         XElements.getSimpleName(identifier.bindingMethod().xprocessing()),
133         identifier.contributingModule().xprocessing().getQualifiedName());
134   }
135 
toModel(dagger.internal.codegen.model.Key key)136   private static Key toModel(dagger.internal.codegen.model.Key key) {
137     return Key.builder(key.type().javac())
138         .qualifier(key.qualifier().map(DaggerAnnotation::javac))
139         .multibindingContributionIdentifier(
140             key.multibindingContributionIdentifier().isPresent()
141                 ? Optional.of(toModel(key.multibindingContributionIdentifier().get()))
142                 : Optional.empty())
143         .build();
144   }
145 
toModel(dagger.internal.codegen.model.BindingKind bindingKind)146   private static BindingKind toModel(dagger.internal.codegen.model.BindingKind bindingKind) {
147     return BindingKind.valueOf(bindingKind.name());
148   }
149 
toModel(dagger.internal.codegen.model.RequestKind requestKind)150   private static RequestKind toModel(dagger.internal.codegen.model.RequestKind requestKind) {
151     return RequestKind.valueOf(requestKind.name());
152   }
153 
toModel( dagger.internal.codegen.model.DependencyRequest request)154   private static DependencyRequest toModel(
155       dagger.internal.codegen.model.DependencyRequest request) {
156     DependencyRequest.Builder builder =
157         DependencyRequest.builder()
158             .kind(toModel(request.kind()))
159             .key(toModel(request.key()))
160             .isNullable(request.isNullable());
161 
162     request.requestElement().ifPresent(e -> builder.requestElement(e.javac()));
163     return builder.build();
164   }
165 
toModel(dagger.internal.codegen.model.Scope scope)166   private static Scope toModel(dagger.internal.codegen.model.Scope scope) {
167     return Scope.scope(scope.scopeAnnotation().javac());
168   }
169 
toModel(dagger.internal.codegen.model.ComponentPath path)170   private static ComponentPath toModel(dagger.internal.codegen.model.ComponentPath path) {
171     return ComponentPath.create(
172         path.components().stream().map(DaggerTypeElement::javac).collect(toImmutableList()));
173   }
174 
toInternal( ComponentNode componentNode)175   private static dagger.internal.codegen.model.BindingGraph.ComponentNode toInternal(
176       ComponentNode componentNode) {
177     return ((ComponentNodeImpl) componentNode).delegate();
178   }
179 
toInternal( MaybeBinding maybeBinding)180   private static dagger.internal.codegen.model.BindingGraph.MaybeBinding toInternal(
181       MaybeBinding maybeBinding) {
182     if (maybeBinding instanceof MissingBindingImpl) {
183       return ((MissingBindingImpl) maybeBinding).delegate();
184     } else if (maybeBinding instanceof BindingNodeImpl) {
185       return ((BindingNodeImpl) maybeBinding).delegate();
186     } else {
187       throw new IllegalStateException("Unhandled binding type: " + maybeBinding.getClass());
188     }
189   }
190 
toInternal( DependencyEdge dependencyEdge)191   private static dagger.internal.codegen.model.BindingGraph.DependencyEdge toInternal(
192       DependencyEdge dependencyEdge) {
193     return ((DependencyEdgeImpl) dependencyEdge).delegate();
194   }
195 
toInternal( ChildFactoryMethodEdge childFactoryMethodEdge)196   private static dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge toInternal(
197       ChildFactoryMethodEdge childFactoryMethodEdge) {
198     return ((ChildFactoryMethodEdgeImpl) childFactoryMethodEdge).delegate();
199   }
200 
201   @AutoValue
202   abstract static class ComponentNodeImpl implements ComponentNode {
create( dagger.internal.codegen.model.BindingGraph.ComponentNode componentNode)203     static ComponentNode create(
204         dagger.internal.codegen.model.BindingGraph.ComponentNode componentNode) {
205       return new AutoValue_ModelBindingGraphConverter_ComponentNodeImpl(
206           toModel(componentNode.componentPath()),
207           componentNode.isSubcomponent(),
208           componentNode.isRealComponent(),
209           componentNode.entryPoints().stream()
210               .map(ModelBindingGraphConverter::toModel)
211               .collect(toImmutableSet()),
212           componentNode.scopes().stream()
213               .map(ModelBindingGraphConverter::toModel)
214               .collect(toImmutableSet()),
215           componentNode);
216     }
217 
delegate()218     abstract dagger.internal.codegen.model.BindingGraph.ComponentNode delegate();
219 
220     @Override
toString()221     public final String toString() {
222       return delegate().toString();
223     }
224   }
225 
226   @AutoValue
227   abstract static class BindingNodeImpl implements Binding {
create(dagger.internal.codegen.model.Binding binding)228     static Binding create(dagger.internal.codegen.model.Binding binding) {
229       return new AutoValue_ModelBindingGraphConverter_BindingNodeImpl(
230           toModel(binding.key()),
231           toModel(binding.componentPath()),
232           binding.dependencies().stream()
233               .map(ModelBindingGraphConverter::toModel)
234               .collect(toImmutableSet()),
235           binding.bindingElement().map(DaggerElement::javac),
236           binding.contributingModule().map(DaggerTypeElement::javac),
237           binding.requiresModuleInstance(),
238           binding.scope().map(ModelBindingGraphConverter::toModel),
239           binding.isNullable(),
240           binding.isProduction(),
241           toModel(binding.kind()),
242           binding);
243     }
244 
delegate()245     abstract dagger.internal.codegen.model.Binding delegate();
246 
247     @Override
toString()248     public final String toString() {
249       return delegate().toString();
250     }
251   }
252 
253   @AutoValue
254   abstract static class MissingBindingImpl extends MissingBinding {
create( dagger.internal.codegen.model.BindingGraph.MissingBinding missingBinding)255     static MissingBinding create(
256         dagger.internal.codegen.model.BindingGraph.MissingBinding missingBinding) {
257       return new AutoValue_ModelBindingGraphConverter_MissingBindingImpl(
258           toModel(missingBinding.componentPath()), toModel(missingBinding.key()), missingBinding);
259     }
260 
delegate()261     abstract dagger.internal.codegen.model.BindingGraph.MissingBinding delegate();
262 
263     @Memoized
264     @Override
hashCode()265     public abstract int hashCode();
266 
267     @Override
equals(Object o)268     public abstract boolean equals(Object o);
269   }
270 
271   @AutoValue
272   abstract static class DependencyEdgeImpl implements DependencyEdge {
create( dagger.internal.codegen.model.BindingGraph.DependencyEdge dependencyEdge)273     static DependencyEdge create(
274         dagger.internal.codegen.model.BindingGraph.DependencyEdge dependencyEdge) {
275       return new AutoValue_ModelBindingGraphConverter_DependencyEdgeImpl(
276           toModel(dependencyEdge.dependencyRequest()),
277           dependencyEdge.isEntryPoint(),
278           dependencyEdge);
279     }
280 
delegate()281     abstract dagger.internal.codegen.model.BindingGraph.DependencyEdge delegate();
282 
283     @Override
toString()284     public final String toString() {
285       return delegate().toString();
286     }
287   }
288 
289   @AutoValue
290   abstract static class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
create( dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge)291     static ChildFactoryMethodEdge create(
292         dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge) {
293       return new AutoValue_ModelBindingGraphConverter_ChildFactoryMethodEdgeImpl(
294           childFactoryMethodEdge.factoryMethod().javac(), childFactoryMethodEdge);
295     }
296 
delegate()297     abstract dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge delegate();
298 
299     @Override
toString()300     public final String toString() {
301       return delegate().toString();
302     }
303   }
304 
305   @AutoValue
306   abstract static class SubcomponentCreatorBindingEdgeImpl
307       implements SubcomponentCreatorBindingEdge {
create( dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge subcomponentCreatorBindingEdge)308     static SubcomponentCreatorBindingEdge create(
309         dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge
310             subcomponentCreatorBindingEdge) {
311       return new AutoValue_ModelBindingGraphConverter_SubcomponentCreatorBindingEdgeImpl(
312           subcomponentCreatorBindingEdge.declaringModules().stream()
313               .map(DaggerTypeElement::javac)
314               .collect(toImmutableSet()),
315           subcomponentCreatorBindingEdge);
316     }
317 
delegate()318     abstract dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge delegate();
319 
320     @Override
toString()321     public final String toString() {
322       return delegate().toString();
323     }
324   }
325 
326   @AutoValue
327   abstract static class BindingGraphImpl extends BindingGraph {
create(dagger.internal.codegen.model.BindingGraph bindingGraph)328     static BindingGraph create(dagger.internal.codegen.model.BindingGraph bindingGraph) {
329       BindingGraphImpl bindingGraphImpl =
330           new AutoValue_ModelBindingGraphConverter_BindingGraphImpl(
331               toModel(bindingGraph.network()), bindingGraph.isFullBindingGraph());
332 
333       bindingGraphImpl.componentNodesByPath =
334           bindingGraphImpl.componentNodes().stream()
335               .collect(toImmutableMap(ComponentNode::componentPath, node -> node));
336 
337       return bindingGraphImpl;
338     }
339 
340     private ImmutableMap<ComponentPath, ComponentNode> componentNodesByPath;
341 
342     // This overrides dagger.model.BindingGraph with a more efficient implementation.
343     @Override
componentNode(ComponentPath componentPath)344     public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
345       return componentNodesByPath.containsKey(componentPath)
346           ? Optional.of(componentNodesByPath.get(componentPath))
347           : Optional.empty();
348     }
349 
350     // This overrides dagger.model.BindingGraph to memoize the output.
351     @Override
352     @Memoized
nodesByClass()353     public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
354       return super.nodesByClass();
355     }
356   }
357 
358   private static final class DiagnosticReporterImpl implements DiagnosticReporter {
create( dagger.internal.codegen.model.DiagnosticReporter reporter)359     static DiagnosticReporterImpl create(
360         dagger.internal.codegen.model.DiagnosticReporter reporter) {
361       return new DiagnosticReporterImpl(reporter);
362     }
363 
364     private final dagger.internal.codegen.model.DiagnosticReporter delegate;
365 
DiagnosticReporterImpl(dagger.internal.codegen.model.DiagnosticReporter delegate)366     DiagnosticReporterImpl(dagger.internal.codegen.model.DiagnosticReporter delegate) {
367       this.delegate = delegate;
368     }
369 
370     @Override
reportComponent( Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message)371     public void reportComponent(
372         Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message) {
373       delegate.reportComponent(diagnosticKind, toInternal(componentNode), message);
374     }
375 
376     @Override
377     @FormatMethod
reportComponent( Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String messageFormat, Object firstArg, Object... moreArgs)378     public void reportComponent(
379         Diagnostic.Kind diagnosticKind,
380         ComponentNode componentNode,
381         String messageFormat,
382         Object firstArg,
383         Object... moreArgs) {
384       delegate.reportComponent(
385           diagnosticKind, toInternal(componentNode), messageFormat, firstArg, moreArgs);
386     }
387 
388     @Override
reportBinding( Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message)389     public void reportBinding(
390         Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
391       delegate.reportBinding(diagnosticKind, toInternal(binding), message);
392     }
393 
394     @Override
395     @FormatMethod
reportBinding( Diagnostic.Kind diagnosticKind, MaybeBinding binding, String messageFormat, Object firstArg, Object... moreArgs)396     public void reportBinding(
397         Diagnostic.Kind diagnosticKind,
398         MaybeBinding binding,
399         String messageFormat,
400         Object firstArg,
401         Object... moreArgs) {
402       delegate.reportBinding(
403           diagnosticKind, toInternal(binding), messageFormat, firstArg, moreArgs);
404     }
405 
406     @Override
reportDependency( Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message)407     public void reportDependency(
408         Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
409       delegate.reportDependency(diagnosticKind, toInternal(dependencyEdge), message);
410     }
411 
412     @Override
413     @FormatMethod
reportDependency( Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String messageFormat, Object firstArg, Object... moreArgs)414     public void reportDependency(
415         Diagnostic.Kind diagnosticKind,
416         DependencyEdge dependencyEdge,
417         String messageFormat,
418         Object firstArg,
419         Object... moreArgs) {
420       delegate.reportDependency(
421           diagnosticKind, toInternal(dependencyEdge), messageFormat, firstArg, moreArgs);
422     }
423 
424     @Override
reportSubcomponentFactoryMethod( Diagnostic.Kind diagnosticKind, ChildFactoryMethodEdge childFactoryMethodEdge, String message)425     public void reportSubcomponentFactoryMethod(
426         Diagnostic.Kind diagnosticKind,
427         ChildFactoryMethodEdge childFactoryMethodEdge,
428         String message) {
429       delegate.reportSubcomponentFactoryMethod(
430           diagnosticKind, toInternal(childFactoryMethodEdge), message);
431     }
432 
433     @Override
434     @FormatMethod
reportSubcomponentFactoryMethod( Diagnostic.Kind diagnosticKind, ChildFactoryMethodEdge childFactoryMethodEdge, String messageFormat, Object firstArg, Object... moreArgs)435     public void reportSubcomponentFactoryMethod(
436         Diagnostic.Kind diagnosticKind,
437         ChildFactoryMethodEdge childFactoryMethodEdge,
438         String messageFormat,
439         Object firstArg,
440         Object... moreArgs) {
441       delegate.reportSubcomponentFactoryMethod(
442           diagnosticKind, toInternal(childFactoryMethodEdge), messageFormat, firstArg, moreArgs);
443     }
444   }
445 }
446