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 TypeVariableName(CharSequence name, Iterable<? extends TypeName> extendsBounds)36 TypeVariableName(CharSequence name, Iterable<? extends TypeName> extendsBounds) { 37 this.name = name; 38 this.extendsBounds = extendsBounds; 39 } 40 name()41 public CharSequence name() { 42 return name; 43 } 44 45 @Override referencedClasses()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 write(Appendable appendable, Context context)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 toString()70 public String toString() { 71 return Writables.writeToString(this); 72 } 73 74 @Override equals(Object obj)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 hashCode()86 public int hashCode() { 87 return Objects.hashCode(name, extendsBounds); 88 } 89 named(CharSequence name)90 static TypeVariableName named(CharSequence name) { 91 return new TypeVariableName(name, ImmutableList.<TypeName>of()); 92 } 93 fromTypeVariable(TypeVariable variable)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). fromTypeParameterElement(TypeParameterElement element)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