Home | History | Annotate | Download | only in codegen
      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 
     70     private Type(Class<?> frameworkClass) {
     71       this.frameworkClass = frameworkClass;
     72     }
     73 
     74     /**
     75      * Returns the framework class associated with bindings of this type.
     76      */
     77     Class<?> frameworkClass() {
     78       return frameworkClass;
     79     }
     80 
     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
     94     public boolean apply(Binding binding) {
     95       return this.equals(binding.bindingType());
     96     }
     97   }
     98 
     99   abstract Binding.Type bindingType();
    100 
    101   /**
    102    * Returns the framework class associated with this binding.
    103    */
    104   Class<?> frameworkClass() {
    105     return bindingType().frameworkClass();
    106   }
    107 
    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. */
    125   protected abstract Key key();
    126 
    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. */
    132   abstract Element bindingElement();
    133 
    134   /** The type enclosing the binding {@link #bindingElement()}. */
    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    */
    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    */
    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    */
    167   abstract Optional<String> bindingPackage();
    168 
    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 
    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    */
    226   abstract boolean hasNonDefaultTypeParameters();
    227 
    228   /**
    229    * The scope of this binding.
    230    */
    231   Scope scope() {
    232     return Scope.unscoped();
    233   }
    234 
    235   // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
    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