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.Suppliers.memoize; 20 import static javax.lang.model.element.Modifier.ABSTRACT; 21 import static javax.lang.model.element.Modifier.STATIC; 22 23 import com.google.common.base.Supplier; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.common.collect.Lists; 27 import com.google.common.collect.Sets; 28 import dagger.internal.codegen.langmodel.DaggerTypes; 29 import dagger.model.BindingKind; 30 import dagger.model.DependencyRequest; 31 import dagger.model.Scope; 32 import java.util.List; 33 import java.util.Optional; 34 import java.util.Set; 35 import javax.lang.model.element.Element; 36 import javax.lang.model.element.Modifier; 37 import javax.lang.model.element.TypeElement; 38 import javax.lang.model.element.TypeParameterElement; 39 import javax.lang.model.type.DeclaredType; 40 import javax.lang.model.type.TypeMirror; 41 import javax.lang.model.util.SimpleTypeVisitor6; 42 43 /** 44 * An abstract type for classes representing a Dagger binding. Particularly, contains the {@link 45 * Element} that generated the binding and the {@link DependencyRequest} instances that are required 46 * to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the 47 * subtypes. 48 */ 49 public abstract class Binding extends BindingDeclaration { 50 51 /** 52 * Returns {@code true} if using this binding requires an instance of the {@link 53 * #contributingModule()}. 54 */ requiresModuleInstance()55 public boolean requiresModuleInstance() { 56 if (!bindingElement().isPresent() || !contributingModule().isPresent()) { 57 return false; 58 } 59 Set<Modifier> modifiers = bindingElement().get().getModifiers(); 60 return !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC); 61 } 62 63 /** 64 * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link 65 * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable() 66 * non-nullable dependency requests}. 67 */ isNullable()68 public abstract boolean isNullable(); 69 70 /** The kind of binding this instance represents. */ kind()71 public abstract BindingKind kind(); 72 73 /** The {@link BindingType} of this binding. */ bindingType()74 public abstract BindingType bindingType(); 75 76 /** The {@link FrameworkType} of this binding. */ frameworkType()77 public final FrameworkType frameworkType() { 78 return FrameworkType.forBindingType(bindingType()); 79 } 80 81 /** 82 * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding as 83 * defined by the user-defined injection sites. 84 */ explicitDependencies()85 public abstract ImmutableSet<DependencyRequest> explicitDependencies(); 86 87 /** 88 * The set of {@link DependencyRequest dependencies} that are added by the framework rather than a 89 * user-defined injection site. This returns an unmodifiable set. 90 */ implicitDependencies()91 public ImmutableSet<DependencyRequest> implicitDependencies() { 92 return ImmutableSet.of(); 93 } 94 95 private final Supplier<ImmutableSet<DependencyRequest>> dependencies = 96 memoize( 97 () -> { 98 ImmutableSet<DependencyRequest> implicitDependencies = implicitDependencies(); 99 return ImmutableSet.copyOf( 100 implicitDependencies.isEmpty() 101 ? explicitDependencies() 102 : Sets.union(implicitDependencies, explicitDependencies())); 103 }); 104 105 /** 106 * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is the 107 * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an 108 * unmodifiable set. 109 */ dependencies()110 public final ImmutableSet<DependencyRequest> dependencies() { 111 return dependencies.get(); 112 } 113 114 /** 115 * If this binding's key's type parameters are different from those of the {@link 116 * #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s unresolved 117 * type. 118 */ unresolved()119 public abstract Optional<? extends Binding> unresolved(); 120 scope()121 public Optional<Scope> scope() { 122 return Optional.empty(); 123 } 124 125 // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror. hasNonDefaultTypeParameters( TypeElement element, TypeMirror type, DaggerTypes types)126 static boolean hasNonDefaultTypeParameters( 127 TypeElement element, TypeMirror type, DaggerTypes types) { 128 // If the element has no type parameters, nothing can be wrong. 129 if (element.getTypeParameters().isEmpty()) { 130 return false; 131 } 132 133 List<TypeMirror> defaultTypes = Lists.newArrayList(); 134 for (TypeParameterElement parameter : element.getTypeParameters()) { 135 defaultTypes.add(parameter.asType()); 136 } 137 138 List<TypeMirror> actualTypes = 139 type.accept( 140 new SimpleTypeVisitor6<List<TypeMirror>, Void>() { 141 @Override 142 protected List<TypeMirror> defaultAction(TypeMirror e, Void p) { 143 return ImmutableList.of(); 144 } 145 146 @Override 147 public List<TypeMirror> visitDeclared(DeclaredType t, Void p) { 148 return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments()); 149 } 150 }, 151 null); 152 153 // The actual type parameter size can be different if the user is using a raw type. 154 if (defaultTypes.size() != actualTypes.size()) { 155 return true; 156 } 157 158 for (int i = 0; i < defaultTypes.size(); i++) { 159 if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) { 160 return true; 161 } 162 } 163 return false; 164 } 165 } 166