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 com.squareup.javapoet; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static com.google.testing.compile.CompilationSubject.assertThat; 20 import static com.google.testing.compile.Compiler.javac; 21 import static javax.lang.model.util.ElementFilter.fieldsIn; 22 import static org.junit.Assert.*; 23 24 import com.google.testing.compile.Compilation; 25 import com.google.testing.compile.JavaFileObjects; 26 import java.io.Serializable; 27 import java.lang.annotation.Annotation; 28 import java.nio.charset.Charset; 29 import java.util.Collections; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Set; 33 import javax.annotation.processing.AbstractProcessor; 34 import javax.annotation.processing.RoundEnvironment; 35 import javax.lang.model.element.AnnotationMirror; 36 import javax.lang.model.element.Element; 37 import javax.lang.model.element.TypeElement; 38 import javax.lang.model.element.TypeParameterElement; 39 import javax.lang.model.element.VariableElement; 40 import javax.lang.model.type.DeclaredType; 41 import javax.lang.model.type.ErrorType; 42 import javax.lang.model.type.TypeKind; 43 import javax.lang.model.type.TypeMirror; 44 import javax.lang.model.type.TypeVisitor; 45 import javax.lang.model.type.WildcardType; 46 import javax.lang.model.util.Elements; 47 import javax.lang.model.util.Types; 48 import javax.tools.JavaFileObject; 49 50 import org.junit.Test; 51 52 public abstract class AbstractTypesTest { getElements()53 protected abstract Elements getElements(); getTypes()54 protected abstract Types getTypes(); 55 getElement(Class<?> clazz)56 private TypeElement getElement(Class<?> clazz) { 57 return getElements().getTypeElement(clazz.getCanonicalName()); 58 } 59 getMirror(Class<?> clazz)60 private TypeMirror getMirror(Class<?> clazz) { 61 return getElement(clazz).asType(); 62 } 63 getBasicTypeMirror()64 @Test public void getBasicTypeMirror() { 65 assertThat(TypeName.get(getMirror(Object.class))) 66 .isEqualTo(ClassName.get(Object.class)); 67 assertThat(TypeName.get(getMirror(Charset.class))) 68 .isEqualTo(ClassName.get(Charset.class)); 69 assertThat(TypeName.get(getMirror(AbstractTypesTest.class))) 70 .isEqualTo(ClassName.get(AbstractTypesTest.class)); 71 } 72 getParameterizedTypeMirror()73 @Test public void getParameterizedTypeMirror() { 74 DeclaredType setType = 75 getTypes().getDeclaredType(getElement(Set.class), getMirror(Object.class)); 76 assertThat(TypeName.get(setType)) 77 .isEqualTo(ParameterizedTypeName.get(ClassName.get(Set.class), ClassName.OBJECT)); 78 } 79 errorTypes()80 @Test public void errorTypes() { 81 JavaFileObject hasErrorTypes = 82 JavaFileObjects.forSourceLines( 83 "com.squareup.tacos.ErrorTypes", 84 "package com.squareup.tacos;", 85 "", 86 "@SuppressWarnings(\"hook-into-compiler\")", 87 "class ErrorTypes {", 88 " Tacos tacos;", 89 " Ingredients.Guacamole guacamole;", 90 "}"); 91 Compilation compilation = javac().withProcessors(new AbstractProcessor() { 92 @Override 93 public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { 94 TypeElement classFile = 95 processingEnv.getElementUtils().getTypeElement("com.squareup.tacos.ErrorTypes"); 96 List<VariableElement> fields = fieldsIn(classFile.getEnclosedElements()); 97 ErrorType topLevel = (ErrorType) fields.get(0).asType(); 98 ErrorType member = (ErrorType) fields.get(1).asType(); 99 100 assertThat(TypeName.get(topLevel)).isEqualTo(ClassName.get("", "Tacos")); 101 assertThat(TypeName.get(member)).isEqualTo(ClassName.get("Ingredients", "Guacamole")); 102 return false; 103 } 104 105 @Override 106 public Set<String> getSupportedAnnotationTypes() { 107 return Collections.singleton("*"); 108 } 109 }).compile(hasErrorTypes); 110 111 assertThat(compilation).failed(); 112 } 113 114 static class Parameterized< 115 Simple, 116 ExtendsClass extends Number, 117 ExtendsInterface extends Runnable, 118 ExtendsTypeVariable extends Simple, 119 Intersection extends Number & Runnable, 120 IntersectionOfInterfaces extends Runnable & Serializable> {} 121 getTypeVariableTypeMirror()122 @Test public void getTypeVariableTypeMirror() { 123 List<? extends TypeParameterElement> typeVariables = 124 getElement(Parameterized.class).getTypeParameters(); 125 126 // Members of converted types use ClassName and not Class<?>. 127 ClassName number = ClassName.get(Number.class); 128 ClassName runnable = ClassName.get(Runnable.class); 129 ClassName serializable = ClassName.get(Serializable.class); 130 131 assertThat(TypeName.get(typeVariables.get(0).asType())) 132 .isEqualTo(TypeVariableName.get("Simple")); 133 assertThat(TypeName.get(typeVariables.get(1).asType())) 134 .isEqualTo(TypeVariableName.get("ExtendsClass", number)); 135 assertThat(TypeName.get(typeVariables.get(2).asType())) 136 .isEqualTo(TypeVariableName.get("ExtendsInterface", runnable)); 137 assertThat(TypeName.get(typeVariables.get(3).asType())) 138 .isEqualTo(TypeVariableName.get("ExtendsTypeVariable", TypeVariableName.get("Simple"))); 139 assertThat(TypeName.get(typeVariables.get(4).asType())) 140 .isEqualTo(TypeVariableName.get("Intersection", number, runnable)); 141 assertThat(TypeName.get(typeVariables.get(5).asType())) 142 .isEqualTo(TypeVariableName.get("IntersectionOfInterfaces", runnable, serializable)); 143 assertThat(((TypeVariableName) TypeName.get(typeVariables.get(4).asType())).bounds) 144 .containsExactly(number, runnable); 145 } 146 147 static class Recursive<T extends Map<List<T>, Set<T[]>>> {} 148 149 @Test getTypeVariableTypeMirrorRecursive()150 public void getTypeVariableTypeMirrorRecursive() { 151 TypeMirror typeMirror = getElement(Recursive.class).asType(); 152 ParameterizedTypeName typeName = (ParameterizedTypeName) TypeName.get(typeMirror); 153 String className = Recursive.class.getCanonicalName(); 154 assertThat(typeName.toString()).isEqualTo(className + "<T>"); 155 156 TypeVariableName typeVariableName = (TypeVariableName) typeName.typeArguments.get(0); 157 158 try { 159 typeVariableName.bounds.set(0, null); 160 fail("Expected UnsupportedOperationException"); 161 } catch (UnsupportedOperationException expected) { 162 } 163 164 assertThat(typeVariableName.toString()).isEqualTo("T"); 165 assertThat(typeVariableName.bounds.toString()) 166 .isEqualTo("[java.util.Map<java.util.List<T>, java.util.Set<T[]>>]"); 167 } 168 getPrimitiveTypeMirror()169 @Test public void getPrimitiveTypeMirror() { 170 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.BOOLEAN))) 171 .isEqualTo(TypeName.BOOLEAN); 172 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.BYTE))) 173 .isEqualTo(TypeName.BYTE); 174 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.SHORT))) 175 .isEqualTo(TypeName.SHORT); 176 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.INT))) 177 .isEqualTo(TypeName.INT); 178 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.LONG))) 179 .isEqualTo(TypeName.LONG); 180 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.CHAR))) 181 .isEqualTo(TypeName.CHAR); 182 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.FLOAT))) 183 .isEqualTo(TypeName.FLOAT); 184 assertThat(TypeName.get(getTypes().getPrimitiveType(TypeKind.DOUBLE))) 185 .isEqualTo(TypeName.DOUBLE); 186 } 187 getArrayTypeMirror()188 @Test public void getArrayTypeMirror() { 189 assertThat(TypeName.get(getTypes().getArrayType(getMirror(Object.class)))) 190 .isEqualTo(ArrayTypeName.of(ClassName.OBJECT)); 191 } 192 getVoidTypeMirror()193 @Test public void getVoidTypeMirror() { 194 assertThat(TypeName.get(getTypes().getNoType(TypeKind.VOID))) 195 .isEqualTo(TypeName.VOID); 196 } 197 getNullTypeMirror()198 @Test public void getNullTypeMirror() { 199 try { 200 TypeName.get(getTypes().getNullType()); 201 fail(); 202 } catch (IllegalArgumentException expected) { 203 } 204 } 205 parameterizedType()206 @Test public void parameterizedType() throws Exception { 207 ParameterizedTypeName type = ParameterizedTypeName.get(Map.class, String.class, Long.class); 208 assertThat(type.toString()).isEqualTo("java.util.Map<java.lang.String, java.lang.Long>"); 209 } 210 arrayType()211 @Test public void arrayType() throws Exception { 212 ArrayTypeName type = ArrayTypeName.of(String.class); 213 assertThat(type.toString()).isEqualTo("java.lang.String[]"); 214 } 215 wildcardExtendsType()216 @Test public void wildcardExtendsType() throws Exception { 217 WildcardTypeName type = WildcardTypeName.subtypeOf(CharSequence.class); 218 assertThat(type.toString()).isEqualTo("? extends java.lang.CharSequence"); 219 } 220 wildcardExtendsObject()221 @Test public void wildcardExtendsObject() throws Exception { 222 WildcardTypeName type = WildcardTypeName.subtypeOf(Object.class); 223 assertThat(type.toString()).isEqualTo("?"); 224 } 225 wildcardSuperType()226 @Test public void wildcardSuperType() throws Exception { 227 WildcardTypeName type = WildcardTypeName.supertypeOf(String.class); 228 assertThat(type.toString()).isEqualTo("? super java.lang.String"); 229 } 230 wildcardMirrorNoBounds()231 @Test public void wildcardMirrorNoBounds() throws Exception { 232 WildcardType wildcard = getTypes().getWildcardType(null, null); 233 TypeName type = TypeName.get(wildcard); 234 assertThat(type.toString()).isEqualTo("?"); 235 } 236 wildcardMirrorExtendsType()237 @Test public void wildcardMirrorExtendsType() throws Exception { 238 Types types = getTypes(); 239 Elements elements = getElements(); 240 TypeMirror charSequence = elements.getTypeElement(CharSequence.class.getName()).asType(); 241 WildcardType wildcard = types.getWildcardType(charSequence, null); 242 TypeName type = TypeName.get(wildcard); 243 assertThat(type.toString()).isEqualTo("? extends java.lang.CharSequence"); 244 } 245 wildcardMirrorSuperType()246 @Test public void wildcardMirrorSuperType() throws Exception { 247 Types types = getTypes(); 248 Elements elements = getElements(); 249 TypeMirror string = elements.getTypeElement(String.class.getName()).asType(); 250 WildcardType wildcard = types.getWildcardType(null, string); 251 TypeName type = TypeName.get(wildcard); 252 assertThat(type.toString()).isEqualTo("? super java.lang.String"); 253 } 254 typeVariable()255 @Test public void typeVariable() throws Exception { 256 TypeVariableName type = TypeVariableName.get("T", CharSequence.class); 257 assertThat(type.toString()).isEqualTo("T"); // (Bounds are only emitted in declaration.) 258 } 259 box()260 @Test public void box() throws Exception { 261 assertThat(TypeName.INT.box()).isEqualTo(ClassName.get(Integer.class)); 262 assertThat(TypeName.VOID.box()).isEqualTo(ClassName.get(Void.class)); 263 assertThat(ClassName.get(Integer.class).box()).isEqualTo(ClassName.get(Integer.class)); 264 assertThat(ClassName.get(Void.class).box()).isEqualTo(ClassName.get(Void.class)); 265 assertThat(TypeName.OBJECT.box()).isEqualTo(TypeName.OBJECT); 266 assertThat(ClassName.get(String.class).box()).isEqualTo(ClassName.get(String.class)); 267 } 268 unbox()269 @Test public void unbox() throws Exception { 270 assertThat(TypeName.INT).isEqualTo(TypeName.INT.unbox()); 271 assertThat(TypeName.VOID).isEqualTo(TypeName.VOID.unbox()); 272 assertThat(ClassName.get(Integer.class).unbox()).isEqualTo(TypeName.INT.unbox()); 273 assertThat(ClassName.get(Void.class).unbox()).isEqualTo(TypeName.VOID.unbox()); 274 try { 275 TypeName.OBJECT.unbox(); 276 fail(); 277 } catch (UnsupportedOperationException expected) { 278 } 279 try { 280 ClassName.get(String.class).unbox(); 281 fail(); 282 } catch (UnsupportedOperationException expected) { 283 } 284 } 285 } 286