xref: /aosp_15_r20/external/auto/common/src/test/java/com/google/auto/common/MoreTypesTest.java (revision 1c2bbba85eccddce6de79cbbf1645fda32e723f0)
1 /*
2  * Copyright 2014 Google LLC
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.google.auto.common;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static java.util.Objects.requireNonNull;
20 import static javax.lang.model.type.TypeKind.NONE;
21 import static javax.lang.model.type.TypeKind.VOID;
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.fail;
24 
25 import com.google.common.base.Optional;
26 import com.google.common.collect.FluentIterable;
27 import com.google.common.collect.ImmutableList;
28 import com.google.common.collect.ImmutableMap;
29 import com.google.common.collect.ImmutableSet;
30 import com.google.common.collect.Iterables;
31 import com.google.common.testing.EquivalenceTester;
32 import com.google.common.truth.Expect;
33 import com.google.testing.compile.CompilationRule;
34 import java.lang.annotation.Annotation;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import javax.lang.model.element.AnnotationMirror;
39 import javax.lang.model.element.Element;
40 import javax.lang.model.element.TypeElement;
41 import javax.lang.model.element.TypeParameterElement;
42 import javax.lang.model.element.VariableElement;
43 import javax.lang.model.type.DeclaredType;
44 import javax.lang.model.type.ErrorType;
45 import javax.lang.model.type.PrimitiveType;
46 import javax.lang.model.type.TypeKind;
47 import javax.lang.model.type.TypeMirror;
48 import javax.lang.model.type.TypeVisitor;
49 import javax.lang.model.type.WildcardType;
50 import javax.lang.model.util.ElementFilter;
51 import javax.lang.model.util.Elements;
52 import javax.lang.model.util.Types;
53 import org.checkerframework.checker.nullness.qual.Nullable;
54 import org.junit.Rule;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.junit.runners.JUnit4;
58 
59 @RunWith(JUnit4.class)
60 public class MoreTypesTest {
61   @Rule public final CompilationRule compilationRule = new CompilationRule();
62   @Rule public final Expect expect = Expect.create();
63 
64   @Test
equivalence()65   public void equivalence() {
66     Types types = compilationRule.getTypes();
67     Elements elements = compilationRule.getElements();
68     TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
69     TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
70     TypeElement mapElement = elements.getTypeElement(Map.class.getCanonicalName());
71     TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
72     TypeElement enumElement = elements.getTypeElement(Enum.class.getCanonicalName());
73     TypeElement container = elements.getTypeElement(Container.class.getCanonicalName());
74     TypeElement contained = elements.getTypeElement(Container.Contained.class.getCanonicalName());
75     TypeElement funkyBounds = elements.getTypeElement(FunkyBounds.class.getCanonicalName());
76     TypeElement funkyBounds2 = elements.getTypeElement(FunkyBounds2.class.getCanonicalName());
77     TypeElement funkierBounds = elements.getTypeElement(FunkierBounds.class.getCanonicalName());
78     TypeMirror funkyBoundsVar = ((DeclaredType) funkyBounds.asType()).getTypeArguments().get(0);
79     TypeMirror funkyBounds2Var = ((DeclaredType) funkyBounds2.asType()).getTypeArguments().get(0);
80     TypeMirror funkierBoundsVar = ((DeclaredType) funkierBounds.asType()).getTypeArguments().get(0);
81     DeclaredType mapOfObjectToObjectType =
82         types.getDeclaredType(mapElement, objectType, objectType);
83     TypeMirror mapType = mapElement.asType();
84     DeclaredType setOfSetOfObject =
85         types.getDeclaredType(setElement, types.getDeclaredType(setElement, objectType));
86     DeclaredType setOfSetOfString =
87         types.getDeclaredType(setElement, types.getDeclaredType(setElement, stringType));
88     DeclaredType setOfSetOfSetOfObject = types.getDeclaredType(setElement, setOfSetOfObject);
89     DeclaredType setOfSetOfSetOfString = types.getDeclaredType(setElement, setOfSetOfString);
90     WildcardType wildcard = types.getWildcardType(null, null);
91     DeclaredType containerOfObject = types.getDeclaredType(container, objectType);
92     DeclaredType containerOfString = types.getDeclaredType(container, stringType);
93     TypeMirror containedInObject = types.asMemberOf(containerOfObject, contained);
94     TypeMirror containedInString = types.asMemberOf(containerOfString, contained);
95     EquivalenceTester<TypeMirror> tester =
96         EquivalenceTester.<TypeMirror>of(MoreTypes.equivalence())
97             .addEquivalenceGroup(types.getNullType())
98             .addEquivalenceGroup(types.getNoType(NONE))
99             .addEquivalenceGroup(types.getNoType(VOID))
100             .addEquivalenceGroup(objectType)
101             .addEquivalenceGroup(stringType)
102             .addEquivalenceGroup(containedInObject)
103             .addEquivalenceGroup(containedInString)
104             .addEquivalenceGroup(funkyBounds.asType())
105             .addEquivalenceGroup(funkyBounds2.asType())
106             .addEquivalenceGroup(funkierBounds.asType())
107             .addEquivalenceGroup(funkyBoundsVar, funkyBounds2Var)
108             .addEquivalenceGroup(funkierBoundsVar)
109             // Enum<E extends Enum<E>>
110             .addEquivalenceGroup(enumElement.asType())
111             // Map<K, V>
112             .addEquivalenceGroup(mapType)
113             .addEquivalenceGroup(mapOfObjectToObjectType)
114             // Map<?, ?>
115             .addEquivalenceGroup(types.getDeclaredType(mapElement, wildcard, wildcard))
116             // Map
117             .addEquivalenceGroup(types.erasure(mapType), types.erasure(mapOfObjectToObjectType))
118             .addEquivalenceGroup(types.getDeclaredType(mapElement, objectType, stringType))
119             .addEquivalenceGroup(types.getDeclaredType(mapElement, stringType, objectType))
120             .addEquivalenceGroup(types.getDeclaredType(mapElement, stringType, stringType))
121             .addEquivalenceGroup(setOfSetOfObject)
122             .addEquivalenceGroup(setOfSetOfString)
123             .addEquivalenceGroup(setOfSetOfSetOfObject)
124             .addEquivalenceGroup(setOfSetOfSetOfString)
125             .addEquivalenceGroup(wildcard)
126             // ? extends Object
127             .addEquivalenceGroup(types.getWildcardType(objectType, null))
128             // ? extends String
129             .addEquivalenceGroup(types.getWildcardType(stringType, null))
130             // ? super String
131             .addEquivalenceGroup(types.getWildcardType(null, stringType))
132             // Map<String, Map<String, Set<Object>>>
133             .addEquivalenceGroup(
134                 types.getDeclaredType(
135                     mapElement,
136                     stringType,
137                     types.getDeclaredType(
138                         mapElement, stringType, types.getDeclaredType(setElement, objectType))))
139             .addEquivalenceGroup(FAKE_ERROR_TYPE);
140 
141     for (TypeKind kind : TypeKind.values()) {
142       if (kind.isPrimitive()) {
143         PrimitiveType primitiveType = types.getPrimitiveType(kind);
144         TypeMirror boxedPrimitiveType = types.boxedClass(primitiveType).asType();
145         tester.addEquivalenceGroup(primitiveType, types.unboxedType(boxedPrimitiveType));
146         tester.addEquivalenceGroup(boxedPrimitiveType);
147         tester.addEquivalenceGroup(types.getArrayType(primitiveType));
148         tester.addEquivalenceGroup(types.getArrayType(boxedPrimitiveType));
149       }
150     }
151 
152     ImmutableSet<Class<?>> testClasses =
153         ImmutableSet.of(
154             ExecutableElementsGroupA.class,
155             ExecutableElementsGroupB.class,
156             ExecutableElementsGroupC.class,
157             ExecutableElementsGroupD.class,
158             ExecutableElementsGroupE.class);
159     for (Class<?> testClass : testClasses) {
160       ImmutableList<TypeMirror> equivalenceGroup =
161           FluentIterable.from(
162                   elements.getTypeElement(testClass.getCanonicalName()).getEnclosedElements())
163               .transform(Element::asType)
164               .toList();
165       tester.addEquivalenceGroup(equivalenceGroup);
166     }
167 
168     tester.test();
169   }
170 
171   @SuppressWarnings("unused")
172   private static final class ExecutableElementsGroupA {
ExecutableElementsGroupA()173     ExecutableElementsGroupA() {}
174 
a()175     void a() {}
176 
b()177     public static void b() {}
178   }
179 
180   @SuppressWarnings("unused")
181   private static final class ExecutableElementsGroupB {
ExecutableElementsGroupB(String s)182     ExecutableElementsGroupB(String s) {}
183 
a(String s)184     void a(String s) {}
185 
b(String s)186     public static void b(String s) {}
187   }
188 
189   @SuppressWarnings("unused")
190   private static final class ExecutableElementsGroupC {
ExecutableElementsGroupC()191     ExecutableElementsGroupC() throws Exception {}
192 
a()193     void a() throws Exception {}
194 
b()195     public static void b() throws Exception {}
196   }
197 
198   @SuppressWarnings("unused")
199   private static final class ExecutableElementsGroupD {
ExecutableElementsGroupD()200     ExecutableElementsGroupD() throws RuntimeException {}
201 
a()202     void a() throws RuntimeException {}
203 
b()204     public static void b() throws RuntimeException {}
205   }
206 
207   @SuppressWarnings("unused")
208   private static final class ExecutableElementsGroupE {
ExecutableElementsGroupE()209     <T> ExecutableElementsGroupE() {}
210 
a()211     <T> void a() {}
212 
b()213     public static <T> void b() {}
214   }
215 
216   @SuppressWarnings("unused")
217   private static final class Container<T> {
218     private final class Contained {}
219   }
220 
221   @SuppressWarnings("unused")
222   private static final class FunkyBounds<T extends Number & Comparable<T>> {}
223 
224   @SuppressWarnings("unused")
225   private static final class FunkyBounds2<T extends Number & Comparable<T>> {}
226 
227   @SuppressWarnings("unused")
228   private static final class FunkierBounds<T extends Number & Comparable<T> & Cloneable> {}
229 
230   @Test
testReferencedTypes()231   public void testReferencedTypes() {
232     Elements elements = compilationRule.getElements();
233     TypeElement testDataElement =
234         elements.getTypeElement(ReferencedTypesTestData.class.getCanonicalName());
235     ImmutableMap<String, VariableElement> fieldIndex =
236         FluentIterable.from(ElementFilter.fieldsIn(testDataElement.getEnclosedElements()))
237             .uniqueIndex(input -> input.getSimpleName().toString());
238 
239     TypeElement objectElement = elements.getTypeElement(Object.class.getCanonicalName());
240     TypeElement stringElement = elements.getTypeElement(String.class.getCanonicalName());
241     TypeElement integerElement = elements.getTypeElement(Integer.class.getCanonicalName());
242     TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
243     TypeElement mapElement = elements.getTypeElement(Map.class.getCanonicalName());
244     TypeElement charSequenceElement =
245         elements.getTypeElement(CharSequence.class.getCanonicalName());
246 
247     assertThat(referencedTypes(fieldIndex, "f1")).containsExactly(objectElement);
248     assertThat(referencedTypes(fieldIndex, "f2")).containsExactly(setElement, stringElement);
249     assertThat(referencedTypes(fieldIndex, "f3"))
250         .containsExactly(mapElement, stringElement, objectElement);
251     assertThat(referencedTypes(fieldIndex, "f4")).containsExactly(integerElement);
252     assertThat(referencedTypes(fieldIndex, "f5")).containsExactly(setElement);
253     assertThat(referencedTypes(fieldIndex, "f6")).containsExactly(setElement, charSequenceElement);
254     assertThat(referencedTypes(fieldIndex, "f7"))
255         .containsExactly(mapElement, stringElement, setElement, charSequenceElement);
256     assertThat(referencedTypes(fieldIndex, "f8")).containsExactly(stringElement);
257     assertThat(referencedTypes(fieldIndex, "f9")).containsExactly(stringElement);
258     assertThat(referencedTypes(fieldIndex, "f10")).isEmpty();
259     assertThat(referencedTypes(fieldIndex, "f11")).isEmpty();
260     assertThat(referencedTypes(fieldIndex, "f12")).containsExactly(setElement, stringElement);
261   }
262 
referencedTypes( ImmutableMap<String, VariableElement> fieldIndex, String fieldName)263   private static ImmutableSet<TypeElement> referencedTypes(
264       ImmutableMap<String, VariableElement> fieldIndex, String fieldName) {
265     VariableElement field = fieldIndex.get(fieldName);
266     requireNonNull(field, fieldName);
267     return MoreTypes.referencedTypes(field.asType());
268   }
269 
270   @SuppressWarnings("unused") // types used in compiler tests
271   private static final class ReferencedTypesTestData {
272     Object f1;
273     Set<String> f2;
274     Map<String, Object> f3;
275     Integer f4;
276     Set<?> f5;
277     Set<? extends CharSequence> f6;
278     Map<String, Set<? extends CharSequence>> f7;
279     String[] f8;
280     String[][] f9;
281     int f10;
282     int[] f11;
283     Set<? super String> f12;
284   }
285 
286   private static class Parent<T> {}
287 
288   private static class ChildA extends Parent<Number> {}
289 
290   private static class ChildB extends Parent<String> {}
291 
292   private static class GenericChild<T> extends Parent<T> {}
293 
294   private interface InterfaceType {}
295 
296   @Test
asElement_throws()297   public void asElement_throws() {
298     TypeMirror javaDotLang = compilationRule.getElements().getPackageElement("java.lang").asType();
299     try {
300       MoreTypes.asElement(javaDotLang);
301       fail();
302     } catch (IllegalArgumentException expected) {
303     }
304   }
305 
306   @Test
asElement()307   public void asElement() {
308     Elements elements = compilationRule.getElements();
309     TypeElement stringElement = elements.getTypeElement("java.lang.String");
310     assertThat(MoreTypes.asElement(stringElement.asType())).isEqualTo(stringElement);
311     TypeParameterElement setParameterElement =
312         Iterables.getOnlyElement(
313             compilationRule.getElements().getTypeElement("java.util.Set").getTypeParameters());
314     assertThat(MoreTypes.asElement(setParameterElement.asType())).isEqualTo(setParameterElement);
315     // we don't test error types because those are very hard to get predictably
316   }
317 
318   @Test
testNonObjectSuperclass()319   public void testNonObjectSuperclass() {
320     Types types = compilationRule.getTypes();
321     Elements elements = compilationRule.getElements();
322     TypeMirror numberType = elements.getTypeElement(Number.class.getCanonicalName()).asType();
323     TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
324     TypeMirror integerType = elements.getTypeElement(Integer.class.getCanonicalName()).asType();
325     TypeElement parent = elements.getTypeElement(Parent.class.getCanonicalName());
326     TypeElement childA = elements.getTypeElement(ChildA.class.getCanonicalName());
327     TypeElement childB = elements.getTypeElement(ChildB.class.getCanonicalName());
328     TypeElement genericChild = elements.getTypeElement(GenericChild.class.getCanonicalName());
329     TypeMirror genericChildOfNumber = types.getDeclaredType(genericChild, numberType);
330     TypeMirror genericChildOfInteger = types.getDeclaredType(genericChild, integerType);
331     TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
332     TypeMirror interfaceType =
333         elements.getTypeElement(InterfaceType.class.getCanonicalName()).asType();
334 
335     assertThat(MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) objectType))
336         .isAbsent();
337     assertThat(MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) interfaceType))
338         .isAbsent();
339     assertThat(MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) parent.asType()))
340         .isAbsent();
341 
342     Optional<DeclaredType> parentOfChildA =
343         MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) childA.asType());
344     Optional<DeclaredType> parentOfChildB =
345         MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) childB.asType());
346     Optional<DeclaredType> parentOfGenericChild =
347         MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) genericChild.asType());
348     Optional<DeclaredType> parentOfGenericChildOfNumber =
349         MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) genericChildOfNumber);
350     Optional<DeclaredType> parentOfGenericChildOfInteger =
351         MoreTypes.nonObjectSuperclass(types, elements, (DeclaredType) genericChildOfInteger);
352 
353     EquivalenceTester<TypeMirror> tester =
354         EquivalenceTester.<TypeMirror>of(MoreTypes.equivalence())
355             .addEquivalenceGroup(
356                 parentOfChildA.get(),
357                 types.getDeclaredType(parent, numberType),
358                 parentOfGenericChildOfNumber.get())
359             .addEquivalenceGroup(parentOfChildB.get(), types.getDeclaredType(parent, stringType))
360             .addEquivalenceGroup(parentOfGenericChild.get(), parent.asType())
361             .addEquivalenceGroup(
362                 parentOfGenericChildOfInteger.get(), types.getDeclaredType(parent, integerType));
363 
364     tester.test();
365   }
366 
367   @Test
testAsMemberOf_variableElement()368   public void testAsMemberOf_variableElement() {
369     Types types = compilationRule.getTypes();
370     Elements elements = compilationRule.getElements();
371     TypeMirror numberType = elements.getTypeElement(Number.class.getCanonicalName()).asType();
372     TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
373     TypeMirror integerType = elements.getTypeElement(Integer.class.getCanonicalName()).asType();
374 
375     TypeElement paramsElement = elements.getTypeElement(Params.class.getCanonicalName());
376     VariableElement tParam =
377         Iterables.getOnlyElement(
378             Iterables.getOnlyElement(ElementFilter.methodsIn(paramsElement.getEnclosedElements()))
379                 .getParameters());
380     VariableElement tField =
381         Iterables.getOnlyElement(ElementFilter.fieldsIn(paramsElement.getEnclosedElements()));
382 
383     DeclaredType numberParams =
384         (DeclaredType) elements.getTypeElement(NumberParams.class.getCanonicalName()).asType();
385     DeclaredType stringParams =
386         (DeclaredType) elements.getTypeElement(StringParams.class.getCanonicalName()).asType();
387     TypeElement genericParams = elements.getTypeElement(GenericParams.class.getCanonicalName());
388     DeclaredType genericParamsOfNumber = types.getDeclaredType(genericParams, numberType);
389     DeclaredType genericParamsOfInteger = types.getDeclaredType(genericParams, integerType);
390 
391     TypeMirror fieldOfNumberParams = MoreTypes.asMemberOf(types, numberParams, tField);
392     TypeMirror paramOfNumberParams = MoreTypes.asMemberOf(types, numberParams, tParam);
393     TypeMirror fieldOfStringParams = MoreTypes.asMemberOf(types, stringParams, tField);
394     TypeMirror paramOfStringParams = MoreTypes.asMemberOf(types, stringParams, tParam);
395     TypeMirror fieldOfGenericOfNumber = MoreTypes.asMemberOf(types, genericParamsOfNumber, tField);
396     TypeMirror paramOfGenericOfNumber = MoreTypes.asMemberOf(types, genericParamsOfNumber, tParam);
397     TypeMirror fieldOfGenericOfInteger =
398         MoreTypes.asMemberOf(types, genericParamsOfInteger, tField);
399     TypeMirror paramOfGenericOfInteger =
400         MoreTypes.asMemberOf(types, genericParamsOfInteger, tParam);
401 
402     EquivalenceTester<TypeMirror> tester =
403         EquivalenceTester.<TypeMirror>of(MoreTypes.equivalence())
404             .addEquivalenceGroup(
405                 fieldOfNumberParams,
406                 paramOfNumberParams,
407                 fieldOfGenericOfNumber,
408                 paramOfGenericOfNumber,
409                 numberType)
410             .addEquivalenceGroup(fieldOfStringParams, paramOfStringParams, stringType)
411             .addEquivalenceGroup(fieldOfGenericOfInteger, paramOfGenericOfInteger, integerType);
412     tester.test();
413   }
414 
415   private static class Params<T> {
416     @SuppressWarnings("unused")
417     T t;
418 
419     @SuppressWarnings("unused")
add(T t)420     void add(T t) {}
421   }
422 
423   private static class NumberParams extends Params<Number> {}
424 
425   private static class StringParams extends Params<String> {}
426 
427   private static class GenericParams<T> extends Params<T> {}
428 
429   private static final ErrorType FAKE_ERROR_TYPE =
430       new ErrorType() {
431         @Override
432         public TypeKind getKind() {
433           return TypeKind.ERROR;
434         }
435 
436         @Override
437         public <R, P> R accept(TypeVisitor<R, P> v, P p) {
438           return v.visitError(this, p);
439         }
440 
441         @Override
442         public ImmutableList<? extends TypeMirror> getTypeArguments() {
443           return ImmutableList.of();
444         }
445 
446         @Override
447         public @Nullable TypeMirror getEnclosingType() {
448           return null;
449         }
450 
451         @Override
452         public @Nullable Element asElement() {
453           return null;
454         }
455 
456         @Override
457         public <A extends Annotation> A @Nullable [] getAnnotationsByType(Class<A> annotationType) {
458           return null;
459         }
460 
461         @Override
462         public <A extends Annotation> @Nullable A getAnnotation(Class<A> annotationType) {
463           return null;
464         }
465 
466         @Override
467         @SuppressWarnings("MutableMethodReturnType")
468         public List<? extends AnnotationMirror> getAnnotationMirrors() {
469           return ImmutableList.of();
470         }
471       };
472 
473   @Test
testIsConversionFromObjectUnchecked_yes()474   public void testIsConversionFromObjectUnchecked_yes() {
475     Elements elements = compilationRule.getElements();
476     TypeElement unchecked = elements.getTypeElement(Unchecked.class.getCanonicalName());
477     for (VariableElement field : ElementFilter.fieldsIn(unchecked.getEnclosedElements())) {
478       TypeMirror type = field.asType();
479       expect
480           .withMessage("Casting to %s is unchecked", type)
481           .that(MoreTypes.isConversionFromObjectUnchecked(type))
482           .isTrue();
483     }
484   }
485 
486   @Test
testIsConversionFromObjectUnchecked_no()487   public void testIsConversionFromObjectUnchecked_no() {
488     Elements elements = compilationRule.getElements();
489     TypeElement notUnchecked = elements.getTypeElement(NotUnchecked.class.getCanonicalName());
490     for (VariableElement field : ElementFilter.fieldsIn(notUnchecked.getEnclosedElements())) {
491       TypeMirror type = field.asType();
492       expect
493           .withMessage("Casting to %s is not unchecked", type)
494           .that(MoreTypes.isConversionFromObjectUnchecked(type))
495           .isFalse();
496     }
497   }
498 
499   @Test
testIsTypeOf()500   public void testIsTypeOf() {
501     Types types = compilationRule.getTypes();
502     PrimitiveType intType = types.getPrimitiveType(TypeKind.INT);
503     TypeMirror integerType = types.boxedClass(intType).asType();
504     WildcardType wildcardType = types.getWildcardType(null, null);
505     expect.that(MoreTypes.isTypeOf(int.class, intType)).isTrue();
506     expect.that(MoreTypes.isTypeOf(Integer.class, integerType)).isTrue();
507     expect.that(MoreTypes.isTypeOf(Integer.class, intType)).isFalse();
508     expect.that(MoreTypes.isTypeOf(int.class, integerType)).isFalse();
509     expect.that(MoreTypes.isTypeOf(Integer.class, FAKE_ERROR_TYPE)).isFalse();
510     assertThrows(
511         IllegalArgumentException.class, () -> MoreTypes.isTypeOf(Integer.class, wildcardType));
512   }
513 
514   // The type of every field here is such that casting to it provokes an "unchecked" warning.
515   @SuppressWarnings("unused")
516   private static class Unchecked<T> {
517     private List<String> listOfString;
518     private List<? extends CharSequence> listOfExtendsCharSequence;
519     private List<? super CharSequence> listOfSuperCharSequence;
520     private List<T> listOfT;
521     private List<T[]> listOfArrayOfT;
522     private T t;
523     private T[] arrayOfT;
524     private List<T>[] arrayOfListOfT;
525     private Map<?, String> mapWildcardToString;
526     private Map<String, ?> mapStringToWildcard;
527   }
528 
529   // The type of every field here is such that casting to it doesn't provoke an "unchecked" warning.
530   @SuppressWarnings("unused")
531   private static class NotUnchecked {
532     private String string;
533     private int integer;
534     private String[] arrayOfString;
535     private int[] arrayOfInt;
536     private Thread.State threadStateEnum;
537     private List<?> listOfWildcard;
538     private List<? extends Object> listOfWildcardExtendsObject;
539     private Map<?, ?> mapWildcardToWildcard;
540   }
541 }
542