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