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