Home | History | Annotate | Download | only in writer
      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.writer;
     17 
     18 import com.google.auto.common.MoreTypes;
     19 import com.google.common.base.Objects;
     20 import com.google.common.base.Predicate;
     21 import com.google.common.collect.FluentIterable;
     22 import com.google.common.collect.ImmutableList;
     23 import com.google.common.collect.ImmutableSet;
     24 import com.google.common.collect.Iterables;
     25 import java.io.IOException;
     26 import java.util.Iterator;
     27 import java.util.Set;
     28 import javax.lang.model.element.TypeParameterElement;
     29 import javax.lang.model.type.TypeMirror;
     30 import javax.lang.model.type.TypeVariable;
     31 
     32 public final class TypeVariableName implements TypeName {
     33   private final CharSequence name;
     34   private final Iterable<? extends TypeName> extendsBounds;
     35 
     36   TypeVariableName(CharSequence name, Iterable<? extends TypeName> extendsBounds) {
     37     this.name = name;
     38     this.extendsBounds = extendsBounds;
     39   }
     40 
     41   public CharSequence name() {
     42     return name;
     43   }
     44 
     45   @Override
     46   public Set<ClassName> referencedClasses() {
     47     ImmutableSet.Builder<ClassName> builder = new ImmutableSet.Builder<ClassName>();
     48     for (TypeName bound : extendsBounds) {
     49       builder.addAll(bound.referencedClasses());
     50     }
     51     return builder.build();
     52   }
     53 
     54   @Override
     55   public Appendable write(Appendable appendable, Context context) throws IOException {
     56     appendable.append(name);
     57     if (!Iterables.isEmpty(extendsBounds)) {
     58       appendable.append(" extends ");
     59       Iterator<? extends TypeName> iter = extendsBounds.iterator();
     60       iter.next().write(appendable, context);
     61       while (iter.hasNext()) {
     62         appendable.append(" & ");
     63         iter.next().write(appendable, context);
     64       }
     65     }
     66     return appendable;
     67   }
     68 
     69   @Override
     70   public String toString() {
     71     return Writables.writeToString(this);
     72   }
     73 
     74   @Override
     75   public boolean equals(Object obj) {
     76     if (obj instanceof TypeVariableName) {
     77       TypeVariableName that = (TypeVariableName) obj;
     78       return this.name.toString().equals(that.name.toString())
     79           && this.extendsBounds.equals(that.extendsBounds);
     80     } else {
     81       return false;
     82     }
     83   }
     84 
     85   @Override
     86   public int hashCode() {
     87     return Objects.hashCode(name, extendsBounds);
     88   }
     89 
     90   static TypeVariableName named(CharSequence name) {
     91     return new TypeVariableName(name, ImmutableList.<TypeName>of());
     92   }
     93 
     94   public static TypeVariableName fromTypeVariable(TypeVariable variable) {
     95     // Note: We don't have any use right now for the bounds because these are references
     96     // to the type & not the specification of the type itself.  We never generate
     97     // code with type variables that include upper or lower bounds.
     98     return named(variable.asElement().getSimpleName());
     99   }
    100 
    101   // TODO(sameb): Consider making this a whole different thing: TypeParameterName since it
    102   // has different semantics than a TypeVariable (parameters only have upper bounds).
    103   public static TypeVariableName fromTypeParameterElement(TypeParameterElement element) {
    104     // We filter out bounds of type Object because those would just clutter the generated code.
    105     Iterable<? extends TypeName> bounds =
    106         FluentIterable.from(element.getBounds())
    107             .filter(new Predicate<TypeMirror>() {
    108               @Override public boolean apply(TypeMirror input) {
    109                 return !MoreTypes.isType(input) || !MoreTypes.isTypeOf(Object.class, input);
    110               }
    111             })
    112             .transform(TypeNames.FOR_TYPE_MIRROR);
    113     return new TypeVariableName(element.getSimpleName(), bounds);
    114   }
    115 }
    116