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