• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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