• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.hilt.processor.internal.root;
18 
19 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
20 
21 import com.google.common.base.Preconditions;
22 import com.google.common.collect.ImmutableList;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Iterables;
25 import com.google.common.graph.GraphBuilder;
26 import com.google.common.graph.Graphs;
27 import com.google.common.graph.ImmutableGraph;
28 import com.google.common.graph.MutableGraph;
29 import com.squareup.javapoet.ClassName;
30 import dagger.hilt.processor.internal.ComponentDescriptor;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Set;
34 
35 /** A representation of the full tree of scopes. */
36 final class ComponentTree {
37   private final ImmutableGraph<ComponentDescriptor> graph;
38   private final ComponentDescriptor root;
39 
40   /** Creates a new tree from a set of descriptors. */
from(Set<ComponentDescriptor> descriptors)41   static ComponentTree from(Set<ComponentDescriptor> descriptors) {
42     MutableGraph<ComponentDescriptor> graph =
43         GraphBuilder.directed().allowsSelfLoops(false).build();
44 
45     descriptors.forEach(
46         descriptor -> {
47           graph.addNode(descriptor);
48           descriptor.parent().ifPresent(parent -> graph.putEdge(parent, descriptor));
49         });
50 
51     return new ComponentTree(ImmutableGraph.copyOf(graph));
52   }
53 
ComponentTree(ImmutableGraph<ComponentDescriptor> graph)54   private ComponentTree(ImmutableGraph<ComponentDescriptor> graph) {
55     this.graph = Preconditions.checkNotNull(graph);
56     Preconditions.checkState(
57         !Graphs.hasCycle(graph),
58         "Component graph has cycles: %s",
59         graph.nodes());
60 
61     // Check that each component has a unique descriptor
62     Map<ClassName, ComponentDescriptor> descriptors = new HashMap<>();
63     for (ComponentDescriptor descriptor : graph.nodes()) {
64       if (descriptors.containsKey(descriptor.component())) {
65         ComponentDescriptor prevDescriptor = descriptors.get(descriptor.component());
66         Preconditions.checkState(
67             // TODO(b/144939893): Use "==" instead of ".equals()"?
68             descriptor.equals(prevDescriptor),
69             "%s has mismatching descriptors:\n"
70             + "    %s\n\n"
71             + "    %s\n\n",
72             prevDescriptor.component(),
73             prevDescriptor,
74             descriptor);
75       }
76       descriptors.put(descriptor.component(), descriptor);
77     }
78 
79     ImmutableList<ComponentDescriptor> roots =
80         graph.nodes().stream()
81             .filter(node -> graph.inDegree(node) == 0)
82             .collect(toImmutableList());
83 
84     Preconditions.checkState(
85         roots.size() == 1,
86         "Component graph must have exactly 1 root. Found: %s",
87         roots.stream().map(ComponentDescriptor::component).collect(toImmutableList()));
88 
89     root = Iterables.getOnlyElement(roots);
90   }
91 
getComponentDescriptors()92   ImmutableSet<ComponentDescriptor> getComponentDescriptors() {
93     return ImmutableSet.copyOf(graph.nodes());
94   }
95 
childrenOf(ComponentDescriptor componentDescriptor)96   ImmutableSet<ComponentDescriptor> childrenOf(ComponentDescriptor componentDescriptor) {
97     return ImmutableSet.copyOf(graph.successors(componentDescriptor));
98   }
99 
graph()100   ImmutableGraph<ComponentDescriptor> graph() {
101     return graph;
102   }
103 
root()104   ComponentDescriptor root() {
105     return root;
106   }
107 }
108