1 /* 2 * Copyright (C) 2014 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.binding; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement; 21 import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; 22 import static dagger.internal.codegen.xprocessing.XElements.isPrivate; 23 import static java.util.stream.Collectors.toList; 24 25 import androidx.room.compiler.processing.XElement; 26 import androidx.room.compiler.processing.XFieldElement; 27 import androidx.room.compiler.processing.XMethodElement; 28 import androidx.room.compiler.processing.XTypeElement; 29 import com.google.auto.value.AutoValue; 30 import com.google.auto.value.extension.memoized.Memoized; 31 import com.google.common.collect.ImmutableSet; 32 import com.google.common.collect.ImmutableSortedSet; 33 import dagger.internal.codegen.model.BindingKind; 34 import dagger.internal.codegen.model.DependencyRequest; 35 import dagger.internal.codegen.model.Key; 36 import java.util.Optional; 37 38 /** Represents the full members injection of a particular type. */ 39 @AutoValue 40 public abstract class MembersInjectionBinding extends Binding { create( Key key, ImmutableSet<DependencyRequest> dependencies, Optional<MembersInjectionBinding> unresolved, ImmutableSortedSet<InjectionSite> injectionSites)41 static MembersInjectionBinding create( 42 Key key, 43 ImmutableSet<DependencyRequest> dependencies, 44 Optional<MembersInjectionBinding> unresolved, 45 ImmutableSortedSet<InjectionSite> injectionSites) { 46 return new AutoValue_MembersInjectionBinding(key, dependencies, unresolved, injectionSites); 47 } 48 49 @Override bindingElement()50 public final Optional<XElement> bindingElement() { 51 return Optional.of(membersInjectedType()); 52 } 53 membersInjectedType()54 public final XTypeElement membersInjectedType() { 55 return key().type().xprocessing().getTypeElement(); 56 } 57 58 @Override unresolved()59 public abstract Optional<MembersInjectionBinding> unresolved(); 60 61 @Override contributingModule()62 public Optional<XTypeElement> contributingModule() { 63 return Optional.empty(); 64 } 65 66 /** The set of individual sites where {@link Inject} is applied. */ injectionSites()67 public abstract ImmutableSortedSet<InjectionSite> injectionSites(); 68 69 @Override bindingType()70 public BindingType bindingType() { 71 return BindingType.MEMBERS_INJECTION; 72 } 73 74 @Override kind()75 public BindingKind kind() { 76 return BindingKind.MEMBERS_INJECTION; 77 } 78 79 @Override isNullable()80 public boolean isNullable() { 81 return false; 82 } 83 84 /** 85 * Returns {@code true} if any of this binding's injection sites are directly on the bound type. 86 */ hasLocalInjectionSites()87 public boolean hasLocalInjectionSites() { 88 return injectionSites().stream() 89 .map(InjectionSite::enclosingTypeElement) 90 .anyMatch(membersInjectedType()::equals); 91 } 92 93 @Override requiresModuleInstance()94 public boolean requiresModuleInstance() { 95 return false; 96 } 97 98 @Memoized 99 @Override hashCode()100 public abstract int hashCode(); 101 102 // TODO(ronshapiro,dpb): simplify the equality semantics 103 @Override equals(Object obj)104 public abstract boolean equals(Object obj); 105 106 /** Metadata about a field or method injection site. */ 107 @AutoValue 108 public abstract static class InjectionSite { 109 /** The type of injection site. */ 110 public enum Kind { 111 FIELD, 112 METHOD, 113 } 114 kind()115 public abstract Kind kind(); 116 element()117 public abstract XElement element(); 118 enclosingTypeElement()119 public abstract XTypeElement enclosingTypeElement(); 120 dependencies()121 public abstract ImmutableSet<DependencyRequest> dependencies(); 122 123 /** 124 * Returns the index of {@link #element()} in its parents {@code @Inject} members that have the 125 * same simple name. This method filters out private elements so that the results will be 126 * consistent independent of whether the build system uses header jars or not. 127 */ 128 @Memoized indexAmongAtInjectMembersWithSameSimpleName()129 public int indexAmongAtInjectMembersWithSameSimpleName() { 130 return enclosingTypeElement().getEnclosedElements().stream() 131 .filter(InjectionAnnotations::hasInjectAnnotation) 132 .filter(element -> !isPrivate(element)) 133 .filter(element -> getSimpleName(element).equals(getSimpleName(this.element()))) 134 .collect(toList()) 135 .indexOf(element()); 136 } 137 field(XFieldElement field, DependencyRequest dependency)138 public static InjectionSite field(XFieldElement field, DependencyRequest dependency) { 139 return create(Kind.FIELD, field, ImmutableSet.of(dependency)); 140 } 141 method( XMethodElement method, Iterable<DependencyRequest> dependencies)142 public static InjectionSite method( 143 XMethodElement method, Iterable<DependencyRequest> dependencies) { 144 return create(Kind.METHOD, method, ImmutableSet.copyOf(dependencies)); 145 } 146 create( Kind kind, XElement element, ImmutableSet<DependencyRequest> dependencies)147 private static InjectionSite create( 148 Kind kind, XElement element, ImmutableSet<DependencyRequest> dependencies) { 149 XTypeElement enclosingTypeElement = checkNotNull(closestEnclosingTypeElement(element)); 150 return new AutoValue_MembersInjectionBinding_InjectionSite( 151 kind, element, enclosingTypeElement, dependencies); 152 } 153 } 154 } 155