1 /* 2 * Copyright (C) 2014 Google, Inc. 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 package dagger.internal.codegen; 17 18 import com.google.auto.common.MoreElements; 19 import com.google.common.base.Optional; 20 import com.google.common.base.Predicate; 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.collect.Lists; 24 import dagger.MembersInjector; 25 import dagger.producers.Producer; 26 import java.util.List; 27 import java.util.Set; 28 import javax.inject.Provider; 29 import javax.lang.model.element.Element; 30 import javax.lang.model.element.ElementVisitor; 31 import javax.lang.model.element.Name; 32 import javax.lang.model.element.PackageElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.TypeParameterElement; 35 import javax.lang.model.type.ArrayType; 36 import javax.lang.model.type.DeclaredType; 37 import javax.lang.model.type.TypeMirror; 38 import javax.lang.model.type.WildcardType; 39 import javax.lang.model.util.SimpleElementVisitor6; 40 import javax.lang.model.util.SimpleTypeVisitor6; 41 import javax.lang.model.util.Types; 42 43 import static javax.lang.model.element.Modifier.PUBLIC; 44 45 /** 46 * An abstract type for classes representing a Dagger binding. Particularly, contains the 47 * {@link Element} that generated the binding and the {@link DependencyRequest} instances that are 48 * required to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding 49 * to the subtypes. 50 * 51 * @author Gregory Kick 52 * @since 2.0 53 */ 54 abstract class Binding { 55 56 /** 57 * The subtype of this binding. 58 */ 59 enum Type implements Predicate<Binding> { 60 /** A binding with this type is a {@link ProvisionBinding}. */ 61 PROVISION(Provider.class), 62 /** A binding with this type is a {@link MembersInjectionBinding}. */ 63 MEMBERS_INJECTION(MembersInjector.class), 64 /** A binding with this type is a {@link ProductionBinding}. */ 65 PRODUCTION(Producer.class), 66 ; 67 68 private final Class<?> frameworkClass; 69 Type(Class<?> frameworkClass)70 private Type(Class<?> frameworkClass) { 71 this.frameworkClass = frameworkClass; 72 } 73 74 /** 75 * Returns the framework class associated with bindings of this type. 76 */ frameworkClass()77 Class<?> frameworkClass() { 78 return frameworkClass; 79 } 80 bindingKeyKind()81 BindingKey.Kind bindingKeyKind() { 82 switch (this) { 83 case MEMBERS_INJECTION: 84 return BindingKey.Kind.MEMBERS_INJECTION; 85 case PROVISION: 86 case PRODUCTION: 87 return BindingKey.Kind.CONTRIBUTION; 88 default: 89 throw new AssertionError(); 90 } 91 } 92 93 @Override apply(Binding binding)94 public boolean apply(Binding binding) { 95 return this.equals(binding.bindingType()); 96 } 97 } 98 bindingType()99 abstract Binding.Type bindingType(); 100 101 /** 102 * Returns the framework class associated with this binding. 103 */ frameworkClass()104 Class<?> frameworkClass() { 105 return bindingType().frameworkClass(); 106 } 107 bindingPackageFor(Iterable<? extends Binding> bindings)108 static Optional<String> bindingPackageFor(Iterable<? extends Binding> bindings) { 109 ImmutableSet.Builder<String> bindingPackagesBuilder = ImmutableSet.builder(); 110 for (Binding binding : bindings) { 111 bindingPackagesBuilder.addAll(binding.bindingPackage().asSet()); 112 } 113 ImmutableSet<String> bindingPackages = bindingPackagesBuilder.build(); 114 switch (bindingPackages.size()) { 115 case 0: 116 return Optional.absent(); 117 case 1: 118 return Optional.of(bindingPackages.iterator().next()); 119 default: 120 throw new IllegalArgumentException(); 121 } 122 } 123 124 /** The {@link Key} that is provided by this binding. */ key()125 protected abstract Key key(); 126 bindingKey()127 BindingKey bindingKey() { 128 return BindingKey.create(bindingType().bindingKeyKind(), key()); 129 } 130 131 /** Returns the {@link Element} instance that is responsible for declaring the binding. */ bindingElement()132 abstract Element bindingElement(); 133 134 /** The type enclosing the binding {@link #bindingElement()}. */ bindingTypeElement()135 TypeElement bindingTypeElement() { 136 return BINDING_TYPE_ELEMENT.visit(bindingElement()); 137 } 138 139 private static final ElementVisitor<TypeElement, Void> BINDING_TYPE_ELEMENT = 140 new SimpleElementVisitor6<TypeElement, Void>() { 141 @Override 142 protected TypeElement defaultAction(Element e, Void p) { 143 return visit(e.getEnclosingElement()); 144 } 145 146 @Override 147 public TypeElement visitType(TypeElement e, Void p) { 148 return e; 149 } 150 }; 151 152 /** 153 * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding. 154 */ dependencies()155 abstract ImmutableSet<DependencyRequest> dependencies(); 156 157 /** 158 * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is a 159 * superset of {@link #dependencies()}. This returns an unmodifiable set. 160 */ implicitDependencies()161 abstract Set<DependencyRequest> implicitDependencies(); 162 163 /** 164 * Returns the name of the package in which this binding must be managed. E.g.: a binding 165 * may reference non-public types. 166 */ bindingPackage()167 abstract Optional<String> bindingPackage(); 168 findBindingPackage(Key bindingKey)169 protected static Optional<String> findBindingPackage(Key bindingKey) { 170 Set<String> packages = nonPublicPackageUse(bindingKey.type()); 171 switch (packages.size()) { 172 case 0: 173 return Optional.absent(); 174 case 1: 175 return Optional.of(packages.iterator().next()); 176 default: 177 throw new IllegalStateException(); 178 } 179 } 180 nonPublicPackageUse(TypeMirror typeMirror)181 private static Set<String> nonPublicPackageUse(TypeMirror typeMirror) { 182 ImmutableSet.Builder<String> packages = ImmutableSet.builder(); 183 typeMirror.accept(new SimpleTypeVisitor6<Void, ImmutableSet.Builder<String>>() { 184 @Override 185 public Void visitArray(ArrayType t, ImmutableSet.Builder<String> p) { 186 return t.getComponentType().accept(this, p); 187 } 188 189 @Override 190 public Void visitDeclared(DeclaredType t, ImmutableSet.Builder<String> p) { 191 for (TypeMirror typeArgument : t.getTypeArguments()) { 192 typeArgument.accept(this, p); 193 } 194 // TODO(gak): address public nested types in non-public types 195 TypeElement typeElement = MoreElements.asType(t.asElement()); 196 if (!typeElement.getModifiers().contains(PUBLIC)) { 197 PackageElement elementPackage = MoreElements.getPackage(typeElement); 198 Name qualifiedName = elementPackage.getQualifiedName(); 199 p.add(qualifiedName.toString()); 200 } 201 // Also make sure enclosing types are visible, otherwise we're fooled by 202 // class Foo { public class Bar } 203 // (Note: we can't use t.getEnclosingType() because it doesn't work!) 204 typeElement.getEnclosingElement().asType().accept(this, p); 205 return null; 206 } 207 208 @Override 209 public Void visitWildcard(WildcardType t, ImmutableSet.Builder<String> p) { 210 if (t.getExtendsBound() != null) { 211 t.getExtendsBound().accept(this, p); 212 } 213 if (t.getSuperBound() != null) { 214 t.getSuperBound().accept(this, p); 215 } 216 return null; 217 } 218 }, packages); 219 return packages.build(); 220 } 221 222 /** 223 * Returns true if this is a binding for a key that has a different type parameter list than the 224 * element it's providing. 225 */ hasNonDefaultTypeParameters()226 abstract boolean hasNonDefaultTypeParameters(); 227 228 /** 229 * The scope of this binding. 230 */ scope()231 Scope scope() { 232 return Scope.unscoped(); 233 } 234 235 // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror. hasNonDefaultTypeParameters(TypeElement element, TypeMirror type, Types types)236 static boolean hasNonDefaultTypeParameters(TypeElement element, TypeMirror type, Types types) { 237 // If the element has no type parameters, nothing can be wrong. 238 if (element.getTypeParameters().isEmpty()) { 239 return false; 240 } 241 242 List<TypeMirror> defaultTypes = Lists.newArrayList(); 243 for (TypeParameterElement parameter : element.getTypeParameters()) { 244 defaultTypes.add(parameter.asType()); 245 } 246 247 List<TypeMirror> actualTypes = 248 type.accept( 249 new SimpleTypeVisitor6<List<TypeMirror>, Void>() { 250 @Override 251 protected List<TypeMirror> defaultAction(TypeMirror e, Void p) { 252 return ImmutableList.of(); 253 } 254 255 @Override 256 public List<TypeMirror> visitDeclared(DeclaredType t, Void p) { 257 return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments()); 258 } 259 }, 260 null); 261 262 // The actual type parameter size can be different if the user is using a raw type. 263 if (defaultTypes.size() != actualTypes.size()) { 264 return true; 265 } 266 267 for (int i = 0; i < defaultTypes.size(); i++) { 268 if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) { 269 return true; 270 } 271 } 272 return false; 273 } 274 } 275