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