1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2018 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.model; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static com.google.common.base.Preconditions.checkState; 20*f585d8a3SJacky Wang import static com.google.common.collect.Iterables.getLast; 21*f585d8a3SJacky Wang import static java.util.stream.Collectors.joining; 22*f585d8a3SJacky Wang 23*f585d8a3SJacky Wang import com.google.auto.value.AutoValue; 24*f585d8a3SJacky Wang import com.google.auto.value.extension.memoized.Memoized; 25*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList; 26*f585d8a3SJacky Wang import javax.lang.model.element.TypeElement; 27*f585d8a3SJacky Wang 28*f585d8a3SJacky Wang /** A path containing a component and all of its ancestor components. */ 29*f585d8a3SJacky Wang @AutoValue 30*f585d8a3SJacky Wang public abstract class ComponentPath { 31*f585d8a3SJacky Wang /** Returns a new {@link ComponentPath} from {@code components}. */ create(Iterable<TypeElement> components)32*f585d8a3SJacky Wang public static ComponentPath create(Iterable<TypeElement> components) { 33*f585d8a3SJacky Wang return new AutoValue_ComponentPath(ImmutableList.copyOf(components)); 34*f585d8a3SJacky Wang } 35*f585d8a3SJacky Wang 36*f585d8a3SJacky Wang /** 37*f585d8a3SJacky Wang * Returns the component types, starting from the {@linkplain #rootComponent() root 38*f585d8a3SJacky Wang * component} and ending with the {@linkplain #currentComponent() current component}. 39*f585d8a3SJacky Wang */ components()40*f585d8a3SJacky Wang public abstract ImmutableList<TypeElement> components(); 41*f585d8a3SJacky Wang 42*f585d8a3SJacky Wang /** 43*f585d8a3SJacky Wang * Returns the root {@code Component}- or {@code ProductionComponent}-annotated type 44*f585d8a3SJacky Wang */ rootComponent()45*f585d8a3SJacky Wang public final TypeElement rootComponent() { 46*f585d8a3SJacky Wang return components().get(0); 47*f585d8a3SJacky Wang } 48*f585d8a3SJacky Wang 49*f585d8a3SJacky Wang /** Returns the component at the end of the path. */ 50*f585d8a3SJacky Wang @Memoized currentComponent()51*f585d8a3SJacky Wang public TypeElement currentComponent() { 52*f585d8a3SJacky Wang return getLast(components()); 53*f585d8a3SJacky Wang } 54*f585d8a3SJacky Wang 55*f585d8a3SJacky Wang /** 56*f585d8a3SJacky Wang * Returns the parent of the {@linkplain #currentComponent()} current component}. 57*f585d8a3SJacky Wang * 58*f585d8a3SJacky Wang * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component} 59*f585d8a3SJacky Wang */ parentComponent()60*f585d8a3SJacky Wang public final TypeElement parentComponent() { 61*f585d8a3SJacky Wang checkState(!atRoot()); 62*f585d8a3SJacky Wang return components().reverse().get(1); 63*f585d8a3SJacky Wang } 64*f585d8a3SJacky Wang 65*f585d8a3SJacky Wang /** 66*f585d8a3SJacky Wang * Returns this path's parent path. 67*f585d8a3SJacky Wang * 68*f585d8a3SJacky Wang * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component} 69*f585d8a3SJacky Wang */ 70*f585d8a3SJacky Wang // TODO(ronshapiro): consider memoizing this parent()71*f585d8a3SJacky Wang public final ComponentPath parent() { 72*f585d8a3SJacky Wang checkState(!atRoot()); 73*f585d8a3SJacky Wang return create(components().subList(0, components().size() - 1)); 74*f585d8a3SJacky Wang } 75*f585d8a3SJacky Wang 76*f585d8a3SJacky Wang /** Returns the path from the root component to the {@code child} of the current component. */ childPath(TypeElement child)77*f585d8a3SJacky Wang public final ComponentPath childPath(TypeElement child) { 78*f585d8a3SJacky Wang return create(ImmutableList.<TypeElement>builder().addAll(components()).add(child).build()); 79*f585d8a3SJacky Wang } 80*f585d8a3SJacky Wang 81*f585d8a3SJacky Wang /** 82*f585d8a3SJacky Wang * Returns {@code true} if the {@linkplain #currentComponent()} current component} is the 83*f585d8a3SJacky Wang * {@linkplain #rootComponent()} root component}. 84*f585d8a3SJacky Wang */ atRoot()85*f585d8a3SJacky Wang public final boolean atRoot() { 86*f585d8a3SJacky Wang return components().size() == 1; 87*f585d8a3SJacky Wang } 88*f585d8a3SJacky Wang 89*f585d8a3SJacky Wang @Override toString()90*f585d8a3SJacky Wang public final String toString() { 91*f585d8a3SJacky Wang return components().stream().map(TypeElement::getQualifiedName).collect(joining(" → ")); 92*f585d8a3SJacky Wang } 93*f585d8a3SJacky Wang 94*f585d8a3SJacky Wang @Memoized 95*f585d8a3SJacky Wang @Override hashCode()96*f585d8a3SJacky Wang public abstract int hashCode(); 97*f585d8a3SJacky Wang 98*f585d8a3SJacky Wang @Override equals(Object obj)99*f585d8a3SJacky Wang public abstract boolean equals(Object obj); 100*f585d8a3SJacky Wang } 101