1 /*
<lambda>null2  * Copyright (C) 2023 The Android Open Source Project
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 
17 package com.android.tools.metalava.model.testsuite.typeitem
18 
19 import com.android.tools.metalava.model.ClassTypeItem
20 import com.android.tools.metalava.model.Codebase
21 import com.android.tools.metalava.model.TypeModifiers
22 import com.android.tools.metalava.model.TypeNullability.NONNULL
23 import com.android.tools.metalava.model.TypeNullability.PLATFORM
24 import com.android.tools.metalava.model.isNullnessAnnotation
25 import com.android.tools.metalava.model.provider.InputFormat
26 import com.android.tools.metalava.model.testsuite.BaseModelTest
27 import com.android.tools.metalava.model.testsuite.assertHasNonNullNullability
28 import com.android.tools.metalava.model.testsuite.assertHasNullableNullability
29 import com.android.tools.metalava.model.testsuite.assertHasPlatformNullability
30 import com.android.tools.metalava.model.testsuite.assertHasUndefinedNullability
31 import com.android.tools.metalava.model.testsuite.runNullabilityTest
32 import com.android.tools.metalava.testing.KnownSourceFiles
33 import com.android.tools.metalava.testing.java
34 import com.android.tools.metalava.testing.kotlin
35 import com.google.common.truth.Truth.assertThat
36 import org.junit.Test
37 
38 class CommonTypeModifiersTest : BaseModelTest() {
39 
40     @Test
41     fun `Test annotation on basic types`() {
42         runCodebaseTest(
43             java(
44                 """
45                     package test.pkg;
46                     public class Foo {
47                         public @A int foo1() {}
48                         public @A String foo2() {}
49                         public <T> @A T foo3() {}
50                     }
51                     @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE)
52                     public @interface A {}
53                 """
54             ),
55             kotlin(
56                 """
57                     package test.pkg
58                     class Foo {
59                         fun foo1(): @A Int {}
60                         fun foo2(): @A String {}
61                         fun <T> foo3(): @A T {}
62                     }
63                     @Target(AnnotationTarget.TYPE)
64                     annotation class A
65                 """
66             ),
67             signature(
68                 """
69                     // Signature format: 2.0
70                     package test.pkg {
71                       public class Foo {
72                         method public @test.pkg.A int foo1();
73                         method public @test.pkg.A String foo2();
74                         method public <T> @test.pkg.A T foo3();
75                       }
76                     }
77                 """
78                     .trimIndent()
79             )
80         ) {
81             val methods = codebase.assertClass("test.pkg.Foo").methods()
82             assertThat(methods).hasSize(3)
83 
84             // @test.pkg.A int
85             val primitiveMethod = methods[0]
86             val primitive = primitiveMethod.returnType()
87             primitive.assertPrimitiveTypeItem {
88                 assertThat(annotationNames()).containsExactly("test.pkg.A")
89             }
90             assertThat(primitiveMethod.annotationNames()).isEmpty()
91 
92             // @test.pkg.A String
93             val stringMethod = methods[1]
94             val string = stringMethod.returnType()
95             string.assertClassTypeItem {
96                 assertThat(annotationNames()).containsExactly("test.pkg.A")
97             }
98             val stringMethodAnnotations = stringMethod.annotationNames()
99             // The Kotlin version puts a nullability annotation on the method
100             if (stringMethodAnnotations.isNotEmpty()) {
101                 assertThat(stringMethodAnnotations)
102                     .containsExactly("org.jetbrains.annotations.NotNull")
103             }
104 
105             // @test.pkg.A T
106             val variableMethod = methods[2]
107             val variable = variableMethod.returnType()
108             val typeParameter = variableMethod.typeParameterList.single()
109             variable.assertReferencesTypeParameter(typeParameter) {
110                 assertThat(annotationNames()).containsExactly("test.pkg.A")
111             }
112             assertThat(variableMethod.annotationNames()).isEmpty()
113         }
114     }
115 
116     @Test
117     fun `Test type-use annotations with multiple allowed targets`() {
118         runCodebaseTest(
119             java(
120                 """
121                     package test.pkg;
122                     public class Foo {
123                         public @A int foo1() {}
124                         public @A String foo2() {}
125                         public @A <T> T foo3() {}
126                     }
127                     @java.lang.annotation.Target({ java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE_USE })
128                     public @interface A {}
129                 """
130             ),
131             kotlin(
132                 """
133                     package test.pkg
134                     class Foo {
135                         @A fun foo(): @A Int {}
136                         @A fun foo(): @A String {}
137                         @A fun <T> foo(): @A T {}
138                     }
139                     @Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
140                     annotation class A
141                 """
142             ),
143             signature(
144                 """
145                     // Signature format: 2.0
146                     package test.pkg {
147                       public class Foo {
148                         method @test.pkg.A public @test.pkg.A int foo1();
149                         method @test.pkg.A public @test.pkg.A String foo2();
150                         method @test.pkg.A public <T> @test.pkg.A T foo3();
151                       }
152                     }
153                 """
154                     .trimIndent()
155             )
156         ) {
157             val methods = codebase.assertClass("test.pkg.Foo").methods()
158             assertThat(methods).hasSize(3)
159 
160             // @test.pkg.A int
161             val primitiveMethod = methods[0]
162             val primitive = primitiveMethod.returnType()
163             primitive.assertPrimitiveTypeItem {
164                 assertThat(annotationNames()).containsExactly("test.pkg.A")
165             }
166             assertThat(primitiveMethod.annotationNames()).containsExactly("test.pkg.A")
167 
168             // @test.pkg.A String
169             val stringMethod = methods[1]
170             val string = stringMethod.returnType()
171             string.assertClassTypeItem {
172                 assertThat(annotationNames()).containsExactly("test.pkg.A")
173             }
174             // The Kotlin version puts a nullability annotation on the method
175             val stringMethodAnnotations =
176                 stringMethod.annotationNames().filter { !isNullnessAnnotation(it.orEmpty()) }
177             assertThat(stringMethodAnnotations).containsExactly("test.pkg.A")
178 
179             // @test.pkg.A T
180             val variableMethod = methods[2]
181             val variable = variableMethod.returnType()
182             val typeParameter = variableMethod.typeParameterList.single()
183             variable.assertReferencesTypeParameter(typeParameter) {
184                 assertThat(annotationNames()).containsExactly("test.pkg.A")
185             }
186             assertThat(variableMethod.annotationNames()).containsExactly("test.pkg.A")
187         }
188     }
189 
190     @Test
191     fun `Test kotlin type-use annotations with multiple allowed targets on non-type target`() {
192         runCodebaseTest(
193             kotlin(
194                 """
195                     package test.pkg
196                     class Foo {
197                         // @A can be applied to a function or type.
198                         // Because of the positioning, it should apply to the function here.
199                         @A fun foo(): Int {}
200                         @A fun foo(): String {}
201                         @A fun <T> foo(): T {}
202                     }
203                     @Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
204                     annotation class A
205                 """
206             )
207         ) {
208             val methods = codebase.assertClass("test.pkg.Foo").methods()
209             assertThat(methods).hasSize(3)
210 
211             val primitiveMethod = methods[0]
212             val primitive = primitiveMethod.returnType()
213             primitive.assertPrimitiveTypeItem { assertThat(annotationNames()).isEmpty() }
214             assertThat(primitiveMethod.annotationNames()).containsExactly("test.pkg.A")
215 
216             val stringMethod = methods[1]
217             val string = stringMethod.returnType()
218             string.assertClassTypeItem { assertThat(annotationNames()).isEmpty() }
219             assertThat(stringMethod.annotationNames())
220                 .containsExactly("org.jetbrains.annotations.NotNull", "test.pkg.A")
221 
222             val variableMethod = methods[2]
223             val variable = variableMethod.returnType()
224             val typeParameter = variableMethod.typeParameterList.single()
225             variable.assertReferencesTypeParameter(typeParameter) {
226                 assertThat(annotationNames()).isEmpty()
227             }
228             assertThat(variableMethod.annotationNames()).containsExactly("test.pkg.A")
229         }
230     }
231 
232     @Test
233     fun `Test filtering of annotations based on target usages`() {
234         runCodebaseTest(
235             java(
236                 """
237                 package test.pkg;
238                 public class Foo {
239                     public @A String bar(@A int arg) {}
240                     public @A String baz;
241                 }
242 
243                 @java.lang.annotation.Target({ java.lang.annotation.ElementType.TYPE_USE, java.lang.annotation.ElementType.PARAMETER })
244                 public @interface A {}
245             """
246                     .trimIndent()
247             )
248         ) {
249             val fooClass = codebase.assertClass("test.pkg.Foo")
250 
251             // @A is TYPE_USE and PARAMETER, so it should not appear on the method
252             val method = fooClass.methods().single()
253             assertThat(method.annotationNames()).isEmpty()
254             val methodReturn = method.returnType()
255             assertThat(methodReturn.annotationNames()).containsExactly("test.pkg.A")
256 
257             // @A is TYPE_USE and PARAMETER, so it should appear on the parameter as well as type
258             val methodParam = method.parameters().single()
259             assertThat(methodParam.annotationNames()).containsExactly("test.pkg.A")
260             val methodParamType = methodParam.type()
261             assertThat(methodParamType.annotationNames()).containsExactly("test.pkg.A")
262 
263             // @A is TYPE_USE and PARAMETER, so it should not appear on the field
264             val field = fooClass.fields().single()
265             assertThat(field.annotationNames()).isEmpty()
266             val fieldType = field.type()
267             assertThat(fieldType.annotationNames()).containsExactly("test.pkg.A")
268         }
269     }
270 
271     @Test
272     fun `Test annotations on qualified class type`() {
273         runCodebaseTest(
274             java(
275                 """
276                     package test.pkg;
277                     public class Foo {
278                         public test.pkg.@test.pkg.A Foo foo() {}
279                     }
280                 """
281             ),
282             signature(
283                 """
284                     // Signature format: 2.0
285                     package test.pkg {
286                       public class Foo {
287                         method public test.pkg.@test.pkg.A Foo foo();
288                       }
289                     }
290                 """
291                     .trimIndent()
292             )
293         ) {
294             val method = codebase.assertClass("test.pkg.Foo").methods().single()
295             assertThat(method.annotationNames()).isEmpty()
296 
297             val returnType = method.returnType()
298             returnType.assertClassTypeItem {
299                 assertThat(qualifiedName).isEqualTo("test.pkg.Foo")
300                 assertThat(annotationNames()).containsExactly("test.pkg.A")
301             }
302         }
303     }
304 
305     @Test
306     fun `Test annotations on class type parameters`() {
307         runCodebaseTest(
308             java(
309                 """
310                     package test.pkg;
311 
312                     public class Foo {
313                         public java.util.@test.pkg.A Map<java.lang.@test.pkg.B @test.pkg.C String, java.lang.@test.pkg.D String> foo() {}
314                     }
315                 """
316             ),
317             signature(
318                 """
319                     // Signature format: 2.0
320                     package test.pkg {
321                       public class Foo {
322                         method public java.util.@test.pkg.A Map<java.lang.@test.pkg.B @test.pkg.C String, java.lang.@test.pkg.D String> foo();
323                       }
324                     }
325                 """
326                     .trimIndent()
327             )
328         ) {
329             val method = codebase.assertClass("test.pkg.Foo").methods().single()
330             assertThat(method.annotationNames()).isEmpty()
331 
332             val mapType = method.returnType()
333             mapType.assertClassTypeItem {
334                 assertThat(annotationNames()).containsExactly("test.pkg.A")
335                 assertThat(arguments).hasSize(2)
336 
337                 // java.lang.@test.pkg.B @test.pkg.C String
338                 val string1 = arguments[0]
339                 assertThat(string1.isString()).isTrue()
340                 assertThat(string1.annotationNames()).containsExactly("test.pkg.B", "test.pkg.C")
341 
342                 // java.lang.@test.pkg.D String
343                 val string2 = arguments[1]
344                 assertThat(string2.isString()).isTrue()
345                 assertThat(string2.annotationNames()).containsExactly("test.pkg.D")
346             }
347         }
348     }
349 
350     @Test
351     fun `Test annotations on array type and component type`() {
352         runCodebaseTest(
353             java(
354                 """
355                     package test.pkg;
356                     public class Foo {
357                         public test.pkg.@test.pkg.A @test.pkg.B Foo @test.pkg.B @test.pkg.C [] foo() {}
358                     }
359                 """
360             ),
361             signature(
362                 """
363                     // Signature format: 2.0
364                     package test.pkg {
365                       public class Foo {
366                         method public test.pkg.@test.pkg.A @test.pkg.B Foo @test.pkg.B @test.pkg.C [] foo();
367                       }
368                     }
369                 """
370                     .trimIndent()
371             )
372         ) {
373             val method = codebase.assertClass("test.pkg.Foo").methods().single()
374             assertThat(method.annotationNames()).isEmpty()
375 
376             val returnType = method.returnType()
377             returnType.assertArrayTypeItem {
378                 assertThat(annotationNames()).containsExactly("test.pkg.B", "test.pkg.C")
379 
380                 componentType.assertClassTypeItem {
381                     assertThat(qualifiedName).isEqualTo("test.pkg.Foo")
382                     assertThat(annotationNames()).containsExactly("test.pkg.A", "test.pkg.B")
383                 }
384             }
385         }
386     }
387 
388     @Test
389     fun `Test leading annotation on array type`() {
390         runCodebaseTest(
391             java(
392                 """
393                     package test.pkg;
394                     public class Foo {
395                         public <T> @test.pkg.A T[] foo() {}
396                     }
397                 """
398             ),
399             signature(
400                 """
401                     // Signature format: 5.0
402                     // - kotlin-name-type-order=yes
403                     // - include-type-use-annotations=yes
404                     package test.pkg {
405                       public class Foo {
406                         method public <T> foo(): @test.pkg.A T[];
407                       }
408                     }
409                 """
410                     .trimIndent()
411             )
412         ) {
413             val method = codebase.assertClass("test.pkg.Foo").methods().single()
414             val methodTypeParam = method.typeParameterList.single()
415             val returnType = method.returnType()
416             returnType.assertArrayTypeItem {
417                 componentType.assertReferencesTypeParameter(methodTypeParam) {
418                     assertThat(annotationNames()).containsExactly("test.pkg.A")
419                 }
420             }
421         }
422     }
423 
424     @Test
425     fun `Test annotations on multidimensional array`() {
426         runCodebaseTest(
427             java(
428                 """
429                     package test.pkg;
430                     public class Foo {
431                         public test.pkg.@test.pkg.A Foo @test.pkg.B [] @test.pkg.C [] @test.pkg.D [] foo() {}
432                     }
433                 """
434                     .trimIndent()
435             ),
436             signature(
437                 """
438                     // Signature format: 2.0
439                     package test.pkg {
440                       public class Foo {
441                         method public test.pkg.@test.pkg.A Foo @test.pkg.B [] @test.pkg.C [] @test.pkg.D [] foo();
442                       }
443                     }
444                 """
445                     .trimIndent()
446             )
447         ) {
448             val method = codebase.assertClass("test.pkg.Foo").methods().single()
449             assertThat(method.annotationNames()).isEmpty()
450 
451             val returnType = method.returnType()
452             // Outer array
453             returnType.assertArrayTypeItem {
454                 assertThat(annotationNames()).containsExactly("test.pkg.B")
455 
456                 // Middle array
457                 componentType.assertArrayTypeItem {
458                     assertThat(annotationNames()).containsExactly("test.pkg.C")
459 
460                     // Inner array
461                     componentType.assertArrayTypeItem {
462                         assertThat(annotationNames()).containsExactly("test.pkg.D")
463 
464                         // Component type
465                         componentType.assertClassTypeItem {
466                             assertThat(qualifiedName).isEqualTo("test.pkg.Foo")
467                             assertThat(annotationNames()).containsExactly("test.pkg.A")
468                         }
469                     }
470                 }
471             }
472         }
473     }
474 
475     @Test
476     fun `Test annotations on multidimensional vararg array`() {
477         runCodebaseTest(
478             java(
479                 """
480                     package test.pkg;
481                     public class Foo {
482                         public void foo(test.pkg.@test.pkg.A Foo @test.pkg.B [] @test.pkg.C [] @test.pkg.D ... arg) {}
483                     }
484                 """
485                     .trimIndent()
486             ),
487             signature(
488                 """
489                     // Signature format: 4.0
490                     package test.pkg {
491                       public class Foo {
492                         method public void foo(test.pkg.@test.pkg.A Foo @test.pkg.B [] @test.pkg.C [] @test.pkg.D ...);
493                       }
494                     }
495                 """
496                     .trimIndent()
497             )
498         ) {
499             val type =
500                 codebase.assertClass("test.pkg.Foo").methods().single().parameters().single().type()
501             type.assertArrayTypeItem {
502                 assertThat(isVarargs).isTrue()
503                 assertThat(annotationNames()).containsExactly("test.pkg.B")
504 
505                 // Middle array
506                 componentType.assertArrayTypeItem {
507                     assertThat(annotationNames()).containsExactly("test.pkg.C")
508 
509                     // Inner array
510                     componentType.assertArrayTypeItem {
511                         assertThat(annotationNames()).containsExactly("test.pkg.D")
512 
513                         // Component type
514                         componentType.assertClassTypeItem {
515                             assertThat(qualifiedName).isEqualTo("test.pkg.Foo")
516                             assertThat(annotationNames()).containsExactly("test.pkg.A")
517                         }
518                     }
519                 }
520             }
521         }
522     }
523 
524     @Test
525     fun `Test inner parameterized types with annotations`() {
526         runCodebaseTest(
527             java(
528                 """
529                     package test.pkg;
530                     public class Outer<O> {
531                         public class Inner<I> {
532                         }
533 
534                         public <P1, P2> test.pkg.@test.pkg.A Outer<@test.pkg.B P1>.@test.pkg.C Inner<@test.pkg.D P2> foo() {
535                             return new Outer<P1>.Inner<P2>();
536                         }
537                     }
538                 """
539             ),
540             signature(
541                 """
542                     // Signature format: 3.0
543                     package test.pkg {
544                       public class Outer<O> {
545                         ctor public Outer();
546                         method public <P1, P2> test.pkg.@test.pkg.A Outer<@test.pkg.B P1!>.@test.pkg.C Inner<@test.pkg.D P2!>! foo();
547                       }
548                       public class Outer.Inner<I> {
549                         ctor public Outer.Inner();
550                       }
551                     }
552                 """
553                     .trimIndent()
554             )
555         ) {
556             val method = codebase.assertClass("test.pkg.Outer").methods().single()
557             val methodTypeParameters = method.typeParameterList
558             assertThat(methodTypeParameters).hasSize(2)
559             val p1 = methodTypeParameters[0]
560             val p2 = methodTypeParameters[1]
561 
562             // Outer<P1>.Inner<P2>
563             val returnType = method.returnType()
564             returnType.assertClassTypeItem {
565                 assertThat(qualifiedName).isEqualTo("test.pkg.Outer.Inner")
566                 assertThat(arguments).hasSize(1)
567                 assertThat(annotationNames()).containsExactly("test.pkg.C")
568 
569                 val innerTypeArgument = arguments.single()
570                 innerTypeArgument.assertReferencesTypeParameter(p2) {
571                     assertThat(name).isEqualTo("P2")
572                     assertThat(annotationNames()).containsExactly("test.pkg.D")
573                 }
574 
575                 outerClassType.assertNotNullTypeItem {
576                     assertThat(qualifiedName).isEqualTo("test.pkg.Outer")
577                     assertThat(outerClassType).isNull()
578                     assertThat(arguments).hasSize(1)
579                     assertThat(annotationNames()).containsExactly("test.pkg.A")
580 
581                     val outerClassArgument = arguments.single()
582                     outerClassArgument.assertReferencesTypeParameter(p1) {
583                         assertThat(name).isEqualTo("P1")
584                         assertThat(annotationNames()).containsExactly("test.pkg.B")
585                     }
586                 }
587             }
588         }
589     }
590 
591     @Test
592     fun `Test interface types`() {
593         runCodebaseTest(
594             java(
595                 """
596                     package test.pkg;
597                     public class Foo implements test.pkg.@test.pkg.A Bar, test.pkg.Baz {}
598                 """
599             ),
600             signature(
601                 """
602                     // Signature format: 4.0
603                     package test.pkg {
604                       public class Foo implements test.pkg.@test.pkg.A Bar, test.pkg.Baz {
605                       }
606                     }
607                 """
608                     .trimIndent()
609             )
610         ) {
611             val foo = codebase.assertClass("test.pkg.Foo")
612             val interfaces = foo.interfaceTypes()
613             assertThat(interfaces).hasSize(2)
614 
615             val bar = interfaces[0]
616             assertThat(bar.qualifiedName).isEqualTo("test.pkg.Bar")
617             val annotations = bar.modifiers.annotations()
618             assertThat(annotations).hasSize(1)
619             assertThat(annotations.single().qualifiedName).isEqualTo("test.pkg.A")
620 
621             val baz = interfaces[1]
622             assertThat(baz.qualifiedName).isEqualTo("test.pkg.Baz")
623         }
624     }
625 
626     @Test
627     fun `Test super class type`() {
628         runCodebaseTest(
629             java(
630                 """
631                     package test.pkg;
632                     public class Foo extends test.pkg.@test.pkg.A Bar {}
633                     class Bar {}
634                     @interface A {}
635                 """
636             ),
637             signature(
638                 """
639                     // Signature format: 4.0
640                     package test.pkg {
641                       public class Foo extends test.pkg.@test.pkg.A Bar {
642                       }
643                       public class Bar {
644                       }
645                       public @interface A {
646                       }
647                     }
648                 """
649                     .trimIndent()
650             )
651         ) {
652             val foo = codebase.assertClass("test.pkg.Foo")
653             val superClass = foo.superClassType()
654             assertThat(superClass).isNotNull()
655             superClass.assertClassTypeItem {
656                 assertThat(qualifiedName).isEqualTo("test.pkg.Bar")
657                 assertThat(annotationNames()).containsExactly("test.pkg.A")
658             }
659         }
660     }
661 
662     @Test
663     fun `Test super class and interface types of interface`() {
664         runCodebaseTest(
665             java(
666                 """
667                     package test.pkg;
668                     public interface Foo extends test.pkg.@test.pkg.A Bar, test.pkg.@test.pkg.B Baz<@test.pkg.C String>, test.pkg.Biz {}
669                 """
670             ),
671             signature(
672                 """
673                     // Signature format: 4.0
674                     package test.pkg {
675                       public interface Foo extends test.pkg.@test.pkg.A Bar test.pkg.@test.pkg.B Baz<@test.pkg.C String> test.pkg.Biz {
676                       }
677                     }
678                 """
679                     .trimIndent()
680             )
681         ) {
682             val foo = codebase.assertClass("test.pkg.Foo")
683             assertThat(foo.superClassType()).isNull()
684 
685             val interfaces = foo.interfaceTypes()
686             assertThat(interfaces).hasSize(3)
687 
688             val bar = interfaces[0]
689             assertThat(bar.qualifiedName).isEqualTo("test.pkg.Bar")
690             assertThat(bar.annotationNames()).containsExactly("test.pkg.A")
691 
692             val baz = interfaces[1]
693             assertThat(baz.qualifiedName).isEqualTo("test.pkg.Baz")
694             assertThat(baz.arguments).hasSize(1)
695             assertThat(baz.annotationNames()).containsExactly("test.pkg.B")
696 
697             val bazTypeArgument = baz.arguments.single()
698             assertThat(bazTypeArgument.isString()).isTrue()
699             assertThat(bazTypeArgument.annotationNames()).containsExactly("test.pkg.C")
700 
701             val biz = interfaces[2]
702             assertThat(biz.qualifiedName).isEqualTo("test.pkg.Biz")
703             assertThat(biz.annotationNames()).isEmpty()
704         }
705     }
706 
707     @Test
708     fun `Test annotated array types in multiple contexts`() {
709         runCodebaseTest(
710             java(
711                 """
712                     package test.pkg;
713                     public class Foo {
714                         public test.pkg.Foo @test.pkg.A [] method(test.pkg.Foo @test.pkg.A [] arg) {}
715                         public test.pkg.Foo @test.pkg.A [] field;
716                     }
717                 """
718             ),
719             signature(
720                 """
721                     // Signature format: 4.0
722                     package test.pkg {
723                       public class Foo {
724                         method public test.pkg.Foo @test.pkg.A [] method(test.pkg.Foo @test.pkg.A []);
725                         field public test.pkg.Foo @test.pkg.A [] field;
726                         property public test.pkg.Foo @test.pkg.A [] prop;
727                       }
728                     }
729                 """
730                     .trimIndent()
731             )
732         ) {
733             val foo = codebase.assertClass("test.pkg.Foo")
734             val method = foo.methods().single()
735             val returnType = method.returnType()
736             val paramType = method.parameters().single().type()
737             val fieldType = foo.fields().single().type()
738             // Properties can't be defined in java, this is only present for signature type
739             val propertyType = foo.properties().singleOrNull()?.type()
740 
741             // Do full check for one type, then verify the others are equal
742             returnType.assertArrayTypeItem {
743                 assertThat(annotationNames()).containsExactly("test.pkg.A")
744 
745                 componentType.assertClassTypeItem {
746                     assertThat(qualifiedName).isEqualTo("test.pkg.Foo")
747                     assertThat(annotationNames()).isEmpty()
748                 }
749             }
750 
751             assertThat(returnType).isEqualTo(paramType)
752             assertThat(returnType).isEqualTo(fieldType)
753             if (propertyType != null) {
754                 assertThat(returnType).isEqualTo(propertyType)
755             }
756         }
757     }
758 
759     @Test
760     fun `Test annotations with spaces in the annotation string`() {
761         runCodebaseTest(
762             signature(
763                 """
764                     // Signature format: 5.0
765                     // - include-type-use-annotations=yes
766                     // - kotlin-name-type-order=yes
767                     package test.pkg {
768                       public class Foo extends test.pkg.@test.pkg.A(a=1, b=2, c=3) Bar implements test.pkg.@test.pkg.A(a=1, b=2, c=3) Baz test.pkg.@test.pkg.A(a=1, b=2, c=3) Biz {
769                         method public <T> foo(_: @test.pkg.A(a=1, b=2, c=3) T @test.pkg.A(a=1, b=2, c=3) []): java.util.@test.pkg.A(a=1, b=2, c=3) List<java.lang.@test.pkg.A(a=1, b=2, c=3) String>;
770                       }
771                     }
772                 """
773                     .trimIndent()
774             )
775         ) {
776             // Check the modifiers contain one annotation, `@test.pkg.A(a=1, b=2, c=3)`
777             val testModifiers = { modifiers: TypeModifiers ->
778                 assertThat(modifiers.annotations()).hasSize(1)
779                 val annotation = modifiers.annotations().single()
780                 assertThat(annotation.qualifiedName).isEqualTo("test.pkg.A")
781                 val attributes = annotation.attributes
782                 assertThat(attributes.toString()).isEqualTo("[a=1, b=2, c=3]")
783             }
784             val fooClass = codebase.assertClass("test.pkg.Foo")
785 
786             val superClass = fooClass.superClassType()
787             superClass.assertNotNullTypeItem {
788                 assertThat(qualifiedName).isEqualTo("test.pkg.Bar")
789                 testModifiers(modifiers)
790             }
791 
792             val interfaces = fooClass.interfaceTypes()
793             val bazInterface = interfaces[0]
794             assertThat(bazInterface.qualifiedName).isEqualTo("test.pkg.Baz")
795             testModifiers(bazInterface.modifiers)
796             val bizInterface = interfaces[1]
797             assertThat(bizInterface.qualifiedName).isEqualTo("test.pkg.Biz")
798             testModifiers(bizInterface.modifiers)
799 
800             val fooMethod = fooClass.methods().single()
801             val typeParam = fooMethod.typeParameterList.single()
802 
803             val parameterType = fooMethod.parameters().single().type()
804             parameterType.assertArrayTypeItem {
805                 testModifiers(modifiers)
806                 componentType.assertReferencesTypeParameter(typeParam) { testModifiers(modifiers) }
807             }
808 
809             val stringList = fooMethod.returnType()
810             stringList.assertClassTypeItem {
811                 assertThat(qualifiedName).isEqualTo("java.util.List")
812                 testModifiers(modifiers)
813 
814                 val string = arguments.single()
815                 assertThat(string.isString()).isTrue()
816                 testModifiers(string.modifiers)
817             }
818         }
819     }
820 
821     @Test
822     fun `Test adding and removing annotations`() {
823         // Not supported for text codebases due to caching
824         runCodebaseTest(
825             java(
826                 """
827                     package test.pkg;
828                     import java.lang.annotation.ElementType;
829                     import java.lang.annotation.Target;
830                     public class Foo {
831                         public @A @B String foo() {}
832                     }
833                     @Target(ElementType.TYPE_USE)
834                     public @interface A {}
835                     @Target(ElementType.TYPE_USE)
836                     public @interface B {}
837                 """
838                     .trimIndent()
839             ),
840         ) {
841             val stringType = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
842             assertThat(stringType.annotationNames()).containsExactly("test.pkg.A", "test.pkg.B")
843 
844             // Remove annotation
845             val annotationA = stringType.modifiers.annotations().first()
846             assertThat(annotationA.qualifiedName).isEqualTo("test.pkg.A")
847             stringType.modifiers.removeAnnotation(annotationA)
848             assertThat(stringType.annotationNames()).containsExactly("test.pkg.B")
849 
850             // Add annotation
851             stringType.modifiers.addAnnotation(annotationA)
852             assertThat(stringType.annotationNames()).containsExactly("test.pkg.B", "test.pkg.A")
853         }
854     }
855 
856     @Test
857     fun `Test nullability of primitives`() {
858         runNullabilityTest(
859             java(
860                 """
861                     package test.pkg;
862                     public class Foo {
863                         public int foo() {}
864                     }
865                 """
866                     .trimIndent()
867             ),
868             signature(
869                 """
870                     // Signature format: 5.0
871                     // - include-type-use-annotations=yes
872                     // - kotlin-name-type-order=yes
873                     // - kotlin-style-nulls=no
874                     package test.pkg {
875                       public class Foo {
876                         method public foo(): int;
877                       }
878                     }
879                 """
880                     .trimIndent()
881             ),
882             kotlin(
883                 """
884                     package test.pkg
885                     class Foo {
886                         fun foo(): Int {}
887                     }
888                 """
889                     .trimIndent()
890             ),
891             signature(
892                 """
893                     // Signature format: 5.0
894                     // - include-type-use-annotations=yes
895                     // - kotlin-name-type-order=yes
896                     package test.pkg {
897                       public class Foo {
898                         method public foo(): int;
899                       }
900                     }
901                 """
902                     .trimIndent()
903             )
904         ) {
905             val primitive = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
906             // Primitives are always non-null without an annotation needed
907             primitive.assertHasNonNullNullability(expectAnnotation = false)
908         }
909     }
910 
911     @Test
912     fun `Test nullability of simple classes`() {
913         runNullabilityTest(
914             java(
915                 """
916                     package test.pkg;
917                     import libcore.util.NonNull;
918                     import libcore.util.Nullable;
919                     public class Foo {
920                         public String platformString() {}
921                         public @Nullable String nullableString() {}
922                         public @NonNull String nonNullString() {}
923                     }
924                 """
925                     .trimIndent()
926             ),
927             signature(
928                 """
929                     // Signature format: 5.0
930                     // - include-type-use-annotations=yes
931                     // - kotlin-name-type-order=yes
932                     // - kotlin-style-nulls=no
933                     package test.pkg {
934                       public class Foo {
935                         method public platformString(): String;
936                         method public nullableString(): @libcore.util.Nullable String;
937                         method public nonNullString(): @libcore.util.NonNull String;
938                       }
939                     }
940                 """
941                     .trimIndent()
942             ),
943             kotlin(
944                 """
945                     package test.pkg
946                     class Foo {
947                         fun nullableString(): String? {}
948                         fun nonNullString(): String {}
949                     }
950                 """
951                     .trimIndent()
952             ),
953             signature(
954                 """
955                     // Signature format: 5.0
956                     // - include-type-use-annotations=yes
957                     // - kotlin-name-type-order=yes
958                     package test.pkg {
959                       public class Foo {
960                         method public platformString(): String!;
961                         method public nullableString(): String?;
962                         method public nonNullString(): String;
963                       }
964                     }
965                 """
966                     .trimIndent()
967             )
968         ) {
969             val fooClass = codebase.assertClass("test.pkg.Foo")
970 
971             // Platform nullability isn't possible from Kotlin
972             if (inputFormat != InputFormat.KOTLIN) {
973                 val platformString = fooClass.assertMethod("platformString", "").returnType()
974                 assertThat(platformString.modifiers.nullability()).isEqualTo(PLATFORM)
975             }
976 
977             val nullableString = fooClass.assertMethod("nullableString", "").returnType()
978             nullableString.assertHasNullableNullability(nullabilityFromAnnotations)
979 
980             val nonNullString = fooClass.assertMethod("nonNullString", "").returnType()
981             nonNullString.assertHasNonNullNullability(nullabilityFromAnnotations)
982         }
983     }
984 
985     @Test
986     fun `Test nullability of arrays`() {
987         runNullabilityTest(
988             java(
989                 """
990                     package test.pkg;
991                     import libcore.util.NonNull;
992                     import libcore.util.Nullable;
993                     public class Foo {
994                         public String[] platformStringPlatformArray() {}
995                         public java.lang.@NonNull String[] nonNullStringPlatformArray() {}
996                         public String @Nullable [] platformStringNullableArray() {}
997                         public java.lang.@Nullable String @Nullable [] nullableStringNullableArray() {}
998                         public java.lang.@Nullable String @NonNull [] nullableStringNonNullArray() {}
999                     }
1000                 """
1001                     .trimIndent()
1002             ),
1003             signature(
1004                 """
1005                     // Signature format: 5.0
1006                     // - include-type-use-annotations=yes
1007                     // - kotlin-name-type-order=yes
1008                     // - kotlin-style-nulls=no
1009                     package test.pkg {
1010                       public class Foo {
1011                         method public nonNullStringPlatformArray(): @NonNull String[];
1012                         method public nullableStringNonNullArray(): @Nullable String @NonNull [];
1013                         method public nullableStringNullableArray(): @Nullable String @Nullable [];
1014                         method public platformStringNullableArray(): String @Nullable [];
1015                         method public platformStringPlatformArray(): String[];
1016                       }
1017                     }
1018                 """
1019                     .trimIndent()
1020             ),
1021             kotlin(
1022                 """
1023                     package test.pkg
1024                     class Foo {
1025                         fun nullableStringNullableArray(): Array<String?>? {}
1026                         fun nullableStringNonNullArray(): Array<String?> {}
1027                     }
1028                 """
1029                     .trimIndent()
1030             ),
1031             signature(
1032                 """
1033                     // Signature format: 5.0
1034                     // - include-type-use-annotations=yes
1035                     // - kotlin-name-type-order=yes
1036                     package test.pkg {
1037                       public class Foo {
1038                         method public nonNullStringPlatformArray(): String[]!;
1039                         method public nullableStringNonNullArray(): String?[];
1040                         method public nullableStringNullableArray(): String?[]?;
1041                         method public platformStringNullableArray(): String![]?;
1042                         method public platformStringPlatformArray(): String![]!;
1043                       }
1044                     }
1045                 """
1046                     .trimIndent()
1047             )
1048         ) {
1049             val fooClass = codebase.assertClass("test.pkg.Foo")
1050 
1051             // Platform nullability isn't possible from Kotlin
1052             if (inputFormat != InputFormat.KOTLIN) {
1053                 val platformStringPlatformArray =
1054                     fooClass.assertMethod("platformStringPlatformArray", "").returnType()
1055                 platformStringPlatformArray.assertArrayTypeItem {
1056                     assertHasPlatformNullability()
1057                     componentType.assertHasPlatformNullability()
1058                 }
1059             }
1060 
1061             // Platform nullability isn't possible from Kotlin
1062             if (inputFormat != InputFormat.KOTLIN) {
1063                 val platformStringNullableArray =
1064                     fooClass.assertMethod("platformStringNullableArray", "").returnType()
1065                 platformStringNullableArray.assertArrayTypeItem {
1066                     assertHasNullableNullability(nullabilityFromAnnotations)
1067                     componentType.assertHasPlatformNullability()
1068                 }
1069             }
1070 
1071             // Platform nullability isn't possible from Kotlin
1072             if (inputFormat != InputFormat.KOTLIN) {
1073                 val nonNullStringPlatformArray =
1074                     fooClass.assertMethod("nonNullStringPlatformArray", "").returnType()
1075                 nonNullStringPlatformArray.assertArrayTypeItem {
1076                     assertHasPlatformNullability()
1077                     componentType.assertHasNonNullNullability(nullabilityFromAnnotations)
1078                 }
1079             }
1080 
1081             val nullableStringNonNullArray =
1082                 fooClass.assertMethod("nullableStringNonNullArray", "").returnType()
1083             nullableStringNonNullArray.assertArrayTypeItem {
1084                 assertHasNonNullNullability(nullabilityFromAnnotations)
1085                 componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1086             }
1087 
1088             val nullableStringNullableArray =
1089                 fooClass.assertMethod("nullableStringNullableArray", "").returnType()
1090             nullableStringNullableArray.assertArrayTypeItem {
1091                 assertHasNullableNullability(nullabilityFromAnnotations)
1092                 componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1093             }
1094         }
1095     }
1096 
1097     @Test
1098     fun `Test nullability of multi-dimensional arrays`() {
1099         runNullabilityTest(
1100             java(
1101                 """
1102                     package test.pkg;
1103                     import libcore.util.NonNull;
1104                     import libcore.util.Nullable;
1105                     public class Foo {
1106                         public java.lang.@Nullable String @NonNull [] @Nullable [] @NonNull [] foo() {}
1107                     }
1108                 """
1109                     .trimIndent()
1110             ),
1111             signature(
1112                 """
1113                     // Signature format: 5.0
1114                     // - include-type-use-annotations=yes
1115                     // - kotlin-name-type-order=yes
1116                     // - kotlin-style-nulls=no
1117                     package test.pkg {
1118                       public class Foo {
1119                         ctor public Foo();
1120                         method public foo(): @Nullable String @NonNull [] @Nullable [] @NonNull [];
1121                       }
1122                     }
1123                 """
1124                     .trimIndent()
1125             ),
1126             kotlin(
1127                 """
1128                     package test.pkg
1129                     class Foo {
1130                         fun foo(): Array<Array<Array<String?>>?>
1131                     }
1132                 """
1133                     .trimIndent()
1134             ),
1135             signature(
1136                 """
1137                     // Signature format: 5.0
1138                     // - include-type-use-annotations=yes
1139                     // - kotlin-name-type-order=yes
1140                     package test.pkg {
1141                       public class Foo {
1142                         ctor public Foo();
1143                         method public foo(): String?[][]?[];
1144                       }
1145                     }
1146                 """
1147                     .trimIndent()
1148             )
1149         ) {
1150             val fooClass = codebase.assertClass("test.pkg.Foo")
1151 
1152             val array3d = fooClass.methods().single().returnType()
1153             array3d.assertArrayTypeItem {
1154                 assertHasNonNullNullability(nullabilityFromAnnotations)
1155 
1156                 componentType.assertArrayTypeItem {
1157                     assertHasNullableNullability(nullabilityFromAnnotations)
1158 
1159                     componentType.assertArrayTypeItem {
1160                         assertHasNonNullNullability(nullabilityFromAnnotations)
1161                         componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1162                     }
1163                 }
1164             }
1165         }
1166     }
1167 
1168     @Test
1169     fun `Test nullability of varargs`() {
1170         runNullabilityTest(
1171             java(
1172                 """
1173                     package test.pkg;
1174                     import libcore.util.NonNull;
1175                     import libcore.util.Nullable;
1176                     public class Foo {
1177                         public void platformStringPlatformVararg(String... arg) {}
1178                         public void nullableStringPlatformVararg(java.lang.@Nullable String... arg) {}
1179                         public void platformStringNullableVararg(String @Nullable ... arg) {}
1180                         public void nullableStringNullableVararg(java.lang.@Nullable String @Nullable ... arg) {}
1181                         public void nullableStringNonNullVararg(java.lang.@Nullable String @NonNull ... arg) {}
1182                     }
1183                 """
1184                     .trimIndent()
1185             ),
1186             signature(
1187                 """
1188                     // Signature format: 5.0
1189                     // - include-type-use-annotations=yes
1190                     // - kotlin-name-type-order=yes
1191                     // - kotlin-style-nulls=no
1192                     package test.pkg {
1193                       public class Foo {
1194                         method public platformStringPlatformVararg(arg: String...): void;
1195                         method public nullableStringPlatformVararg(arg: @Nullable String...): void;
1196                         method public platformStringNullableVararg(arg: String @Nullable ...): void;
1197                         method public nullableStringNullableVararg(arg: @Nullable String @Nullable ...): void;
1198                         method public nullableStringNonNullVararg(arg: @Nullable String @NonNull ...): void;
1199                       }
1200                     }
1201                 """
1202                     .trimIndent()
1203             ),
1204             kotlin(
1205                 """
1206                     package test.pkg
1207                     class Foo {
1208                         // Platform nullability isn't possible
1209                         // Nullable varargs aren't possible
1210                         fun nullableStringNonNullVararg(vararg arg: String?) = Unit
1211                     }
1212                 """
1213                     .trimIndent()
1214             ),
1215             signature(
1216                 """
1217                     // Signature format: 5.0
1218                     // - include-type-use-annotations=yes
1219                     // - kotlin-name-type-order=yes
1220                     package test.pkg {
1221                       public class Foo {
1222                         method public platformStringPlatformVararg(arg: String!...!): void;
1223                         method public nullableStringPlatformVararg(arg: String?...!): void;
1224                         method public platformStringNullableVararg(arg: String!...?): void;
1225                         method public nullableStringNullableVararg(arg: String?...?): void;
1226                         method public nullableStringNonNullVararg(arg: String?...): void;
1227                       }
1228                     }
1229                 """
1230                     .trimIndent()
1231             )
1232         ) {
1233             val fooClass = codebase.assertClass("test.pkg.Foo")
1234 
1235             if (inputFormat != InputFormat.KOTLIN) {
1236                 val platformStringPlatformVararg =
1237                     fooClass
1238                         .assertMethod("platformStringPlatformVararg", "java.lang.String[]")
1239                         .parameters()
1240                         .single()
1241                         .type()
1242                 platformStringPlatformVararg.assertArrayTypeItem {
1243                     assertHasPlatformNullability()
1244                     componentType.assertHasPlatformNullability()
1245                 }
1246             }
1247 
1248             if (inputFormat != InputFormat.KOTLIN) {
1249                 val nullableStringPlatformVararg =
1250                     fooClass
1251                         .assertMethod("nullableStringPlatformVararg", "java.lang.String[]")
1252                         .parameters()
1253                         .single()
1254                         .type()
1255                 nullableStringPlatformVararg.assertArrayTypeItem {
1256                     assertHasPlatformNullability()
1257                     componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1258                 }
1259             }
1260 
1261             if (inputFormat != InputFormat.KOTLIN) {
1262                 val platformStringNullableVararg =
1263                     fooClass
1264                         .assertMethod("platformStringNullableVararg", "java.lang.String[]")
1265                         .parameters()
1266                         .single()
1267                         .type()
1268                 platformStringNullableVararg.assertArrayTypeItem {
1269                     assertHasNullableNullability(nullabilityFromAnnotations)
1270                     componentType.assertHasPlatformNullability()
1271                 }
1272             }
1273 
1274             if (inputFormat != InputFormat.KOTLIN) {
1275                 val nullableStringNullableVararg =
1276                     fooClass
1277                         .assertMethod("nullableStringNullableVararg", "java.lang.String[]")
1278                         .parameters()
1279                         .single()
1280                         .type()
1281                 nullableStringNullableVararg.assertArrayTypeItem {
1282                     assertHasNullableNullability(nullabilityFromAnnotations)
1283                     componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1284                 }
1285             }
1286 
1287             // The only version that exists for Kotlin
1288             val nullableStringNonNullVararg =
1289                 fooClass
1290                     .assertMethod("nullableStringNonNullVararg", "java.lang.String[]")
1291                     .parameters()
1292                     .single()
1293                     .type()
1294             nullableStringNonNullVararg.assertHasNonNullNullability(nullabilityFromAnnotations)
1295             nullableStringNonNullVararg.assertArrayTypeItem {
1296                 componentType.assertHasNullableNullability(nullabilityFromAnnotations)
1297             }
1298         }
1299     }
1300 
1301     @Test
1302     fun `Test nullability of classes with parameters`() {
1303         runNullabilityTest(
1304             java(
1305                 """
1306                     package test.pkg;
1307                     import java.util.List;
1308                     import java.util.Map;
1309                     import libcore.util.NonNull;
1310                     import libcore.util.Nullable;
1311                     public class Foo {
1312                         public @Nullable List<String> nullableListPlatformString() {}
1313                         public @NonNull List<@Nullable String> nonNullListNullableString() {}
1314                         public @Nullable Map<@NonNull Integer, @Nullable String> nullableMap() {}
1315                     }
1316                 """
1317                     .trimIndent()
1318             ),
1319             signature(
1320                 """
1321                     // Signature format: 5.0
1322                     // - include-type-use-annotations=yes
1323                     // - kotlin-name-type-order=yes
1324                     // - kotlin-style-nulls=no
1325                     package test.pkg {
1326                       public class Foo {
1327                         method public nullableListPlatformString(): java.util.@Nullable List<java.lang.String>;
1328                         method public nonNullListNullableString(): java.util.@NonNull List<java.lang.@Nullable String>;
1329                         method public nullableMap(): java.util.@Nullable Map<java.lang.@NonNull Integer, java.lang.@Nullable String>;
1330                       }
1331                     }
1332                 """
1333                     .trimIndent()
1334             ),
1335             kotlin(
1336                 """
1337                     package test.pkg
1338                     class Foo {
1339                         fun nonNullListNullableString(): List<String?> {}
1340                         fun nullableMap(): Map<Int, String?>? {}
1341                     }
1342                 """
1343                     .trimIndent()
1344             ),
1345             signature(
1346                 """
1347                     // Signature format: 5.0
1348                     // - include-type-use-annotations=yes
1349                     // - kotlin-name-type-order=yes
1350                     package test.pkg {
1351                       public class Foo {
1352                         method public nullableListPlatformString(): java.util.List<java.lang.String!>?;
1353                         method public nonNullListNullableString(): java.util.List<java.lang.String?>;
1354                         method public nullableMap(): java.util.Map<java.lang.Integer, java.lang.String?>?;
1355                       }
1356                     }
1357                 """
1358                     .trimIndent()
1359             )
1360         ) {
1361             val fooClass = codebase.assertClass("test.pkg.Foo")
1362 
1363             // Platform type doesn't exist in Kotlin
1364             if (inputFormat != InputFormat.KOTLIN) {
1365                 val nullableListPlatformString =
1366                     fooClass.assertMethod("nullableListPlatformString", "").returnType()
1367                 nullableListPlatformString.assertClassTypeItem {
1368                     assertHasNullableNullability(nullabilityFromAnnotations)
1369                     arguments.single().assertHasPlatformNullability()
1370                 }
1371             }
1372 
1373             val nonNullListNullableString =
1374                 fooClass.assertMethod("nonNullListNullableString", "").returnType()
1375             nonNullListNullableString.assertClassTypeItem {
1376                 assertHasNonNullNullability(nullabilityFromAnnotations)
1377                 arguments.single().assertHasNullableNullability(nullabilityFromAnnotations)
1378             }
1379 
1380             val nullableMap = fooClass.assertMethod("nullableMap", "").returnType()
1381             nullableMap.assertClassTypeItem {
1382                 assertHasNullableNullability(nullabilityFromAnnotations)
1383                 // Non-null Integer
1384                 arguments[0].assertHasNonNullNullability(nullabilityFromAnnotations)
1385                 // Nullable String
1386                 arguments[1].assertHasNullableNullability(nullabilityFromAnnotations)
1387             }
1388         }
1389     }
1390 
1391     @Test
1392     fun `Test nullability of outer classes`() {
1393         runNullabilityTest(
1394             java(
1395                 """
1396                     package test.pkg;
1397                     import libcore.util.NonNull;
1398                     import libcore.util.Nullable;
1399                     public class Foo {
1400                         public Outer<@Nullable String>.@Nullable Inner<@NonNull String> foo();
1401                     }
1402                     public class Outer<P1> {
1403                         public class Inner<P2> {}
1404                     }
1405                 """
1406                     .trimIndent()
1407             ),
1408             signature(
1409                 """
1410                     // Signature format: 5.0
1411                     // - include-type-use-annotations=yes
1412                     // - kotlin-name-type-order=yes
1413                     // - kotlin-style-nulls=no
1414                     package test.pkg {
1415                       public class Foo {
1416                         method public foo(): test.pkg.Outer<java.lang.@libcore.util.Nullable String>.@libcore.util.Nullable Inner<java.lang.@libcore.util.NonNull String>;
1417                       }
1418                     }
1419                 """
1420                     .trimIndent()
1421             ),
1422             kotlin(
1423                 """
1424                     package test.pkg
1425                     class Foo {
1426                         fun foo(): Outer<String?>.Inner<String>? {}
1427                     }
1428                     class Outer<P1> {
1429                         inner class Inner<P2>
1430                     }
1431                 """
1432                     .trimIndent()
1433             ),
1434             signature(
1435                 """
1436                     // Signature format: 5.0
1437                     // - include-type-use-annotations=yes
1438                     // - kotlin-name-type-order=yes
1439                     package test.pkg {
1440                       public class Foo {
1441                         method public foo(): test.pkg.Outer<java.lang.String?>.Inner<java.lang.String>?;
1442                       }
1443                     }
1444                 """
1445                     .trimIndent()
1446             ),
1447         ) {
1448             val innerClass = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1449             innerClass.assertClassTypeItem {
1450                 assertHasNullableNullability(nullabilityFromAnnotations)
1451                 arguments.single().assertHasNonNullNullability(nullabilityFromAnnotations)
1452 
1453                 // Outer class types can't be null and don't need to be annotated.
1454                 outerClassType.assertNotNullTypeItem {
1455                     assertHasNonNullNullability(expectAnnotation = false)
1456                     arguments.single().assertHasNullableNullability(nullabilityFromAnnotations)
1457                 }
1458             }
1459         }
1460     }
1461 
1462     @Test
1463     fun `Test nullability of wildcards`() {
1464         runNullabilityTest(
1465             java(
1466                 """
1467                     package test.pkg;
1468                     import libcore.util.NonNull;
1469                     import libcore.util.Nullable;
1470                     import java.util.List;
1471                     public class Foo<T> {
1472                         public @NonNull Foo<? extends @Nullable String> extendsBound() {}
1473                         public @NonNull Foo<? super @NonNull String> superBound() {}
1474                         public @NonNull Foo<?> unbounded() {}
1475                     }
1476                 """
1477                     .trimIndent()
1478             ),
1479             signature(
1480                 """
1481                     // Signature format: 5.0
1482                     // - kotlin-name-type-order=yes
1483                     // - include-type-use-annotations=yes
1484                     // - kotlin-style-nulls=no
1485                     package test.pkg {
1486                       public class Foo<T> {
1487                         method public extendsBound(): test.pkg.@NonNull Foo<? extends java.lang.@Nullable String>;
1488                         method public superBound(): test.pkg.@NonNull Foo<? super java.lang.@NonNull String>;
1489                         method public unbounded(): test.pkg.@NonNull Foo<?>;
1490                       }
1491                     }
1492                 """
1493                     .trimIndent()
1494             ),
1495             kotlin(
1496                 """
1497                     package test.pkg
1498                     class Foo<T> {
1499                         fun extendsBound(): Foo<out String?> {}
1500                         fun superBound(): Foo<in String> {}
1501                         fun unbounded(): Foo<*> {}
1502                     }
1503                 """
1504                     .trimIndent()
1505             ),
1506             signature(
1507                 """
1508                     // Signature format: 5.0
1509                     // - kotlin-name-type-order=yes
1510                     // - include-type-use-annotations=yes
1511                     package test.pkg {
1512                       public class Foo<T> {
1513                         method public extendsBound(): test.pkg.Foo<? extends java.lang.String?>;
1514                         method public superBound(): test.pkg.Foo<? super java.lang.String>;
1515                         method public unbounded(): test.pkg.Foo<?>;
1516                       }
1517                     }
1518                 """
1519                     .trimIndent()
1520             )
1521         ) {
1522             val fooClass = codebase.assertClass("test.pkg.Foo")
1523 
1524             val extendsBoundReturnType = fooClass.assertMethod("extendsBound", "").returnType()
1525             extendsBoundReturnType.assertClassTypeItem {
1526                 assertHasNonNullNullability(nullabilityFromAnnotations)
1527 
1528                 val argumentType = arguments.single()
1529                 argumentType.assertWildcardItem {
1530                     assertHasUndefinedNullability()
1531                     extendsBound.assertNotNullTypeItem {
1532                         assertHasNullableNullability(nullabilityFromAnnotations)
1533                     }
1534                 }
1535             }
1536 
1537             val superBoundReturnType = fooClass.assertMethod("superBound", "").returnType()
1538             superBoundReturnType.assertClassTypeItem {
1539                 assertHasNonNullNullability(nullabilityFromAnnotations)
1540 
1541                 val argumentType = arguments.single()
1542                 argumentType.assertWildcardItem {
1543                     assertHasUndefinedNullability()
1544                     superBound.assertNotNullTypeItem {
1545                         assertHasNonNullNullability(nullabilityFromAnnotations)
1546                     }
1547                 }
1548             }
1549 
1550             val unboundedReturnType = fooClass.assertMethod("unbounded", "").returnType()
1551             unboundedReturnType.assertClassTypeItem {
1552                 assertHasNonNullNullability(nullabilityFromAnnotations)
1553 
1554                 val argumentType = arguments.single()
1555                 argumentType.assertHasUndefinedNullability()
1556             }
1557         }
1558     }
1559 
1560     @Test
1561     fun `Test resetting nullability`() {
1562         // Mutating modifiers isn't supported for a text codebase due to type caching.
1563         val javaSource =
1564             inputSet(
1565                 java(
1566                     """
1567                         package test.pkg;
1568                         import libcore.util.Nullable;
1569                         public class Foo {
1570                             public java.lang.@Nullable String foo() {}
1571                         }
1572                     """
1573                         .trimIndent()
1574                 ),
1575                 KnownSourceFiles.libcoreNullableSource
1576             )
1577         val kotlinSource =
1578             kotlin(
1579                 """
1580                     package test.pkg
1581                     class Foo {
1582                         fun foo(): String? {}
1583                     }
1584                 """
1585                     .trimIndent()
1586             )
1587         val nullabilityTest = { codebase: Codebase, annotations: Boolean ->
1588             val stringType = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1589             // The type is originally nullable
1590             stringType.assertHasNullableNullability(annotations)
1591 
1592             // Set to platform
1593             stringType.modifiers.setNullability(PLATFORM)
1594             stringType.assertHasPlatformNullability()
1595             // The annotation was not removed
1596             if (annotations) {
1597                 assertThat(stringType.annotationNames().single()).endsWith("Nullable")
1598             }
1599 
1600             // Set to non-null
1601             stringType.modifiers.setNullability(NONNULL)
1602             assertThat(stringType.modifiers.nullability()).isEqualTo(NONNULL)
1603             // The nullable annotation was not removed, a nonnull annotation was not added
1604             if (annotations) {
1605                 assertThat(stringType.annotationNames().single()).endsWith("Nullable")
1606             }
1607         }
1608 
1609         runCodebaseTest(javaSource) { nullabilityTest(codebase, true) }
1610         runCodebaseTest(kotlinSource) { nullabilityTest(codebase, false) }
1611     }
1612 
1613     @Test
1614     fun `Test nullability set through item annotations`() {
1615         runCodebaseTest(
1616             inputSet(
1617                 java(
1618                     """
1619                         package test.pkg;
1620                         import org.jetbrains.annotations.Nullable;
1621                         public class Foo {
1622                             public @Nullable String foo() {}
1623                         }
1624                     """
1625                         .trimIndent()
1626                 ),
1627                 java(
1628                     """
1629                         package org.jetbrains.annotations;
1630                         import java.lang.annotation.ElementType;
1631                         import java.lang.annotation.Target;
1632                         @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
1633                         public @interface Nullable {}
1634                     """
1635                         .trimIndent()
1636                 )
1637             ),
1638             inputSet(
1639                 signature(
1640                     """
1641                         // Signature format: 5.0
1642                         // - kotlin-name-type-order=yes
1643                         // - include-type-use-annotations=yes
1644                         // - kotlin-style-nulls=no
1645                         package test.pkg {
1646                           public class Foo {
1647                             method @Nullable public foo(): String;
1648                           }
1649                         }
1650                     """
1651                         .trimIndent()
1652                 )
1653             )
1654         ) {
1655             val strType = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1656             // The annotation is on the item, not the type.
1657             strType.assertHasNullableNullability(expectAnnotation = false)
1658         }
1659     }
1660 
1661     @Test
1662     fun `Test implicit nullability of constants`() {
1663         runCodebaseTest(
1664             java(
1665                 """
1666                 package test.pkg;
1667                 public class Foo {
1668                     public final String nonNullStringConstant = "non null value";
1669                     public final String nullStringConstant = null;
1670                     public String nonConstantString = "non null value";
1671                 }
1672             """
1673                     .trimIndent()
1674             ),
1675             signature(
1676                 """
1677                 // Signature format: 2.0
1678                 package test.pkg {
1679                   public class Foo {
1680                     field public final String nonNullStringConstant = "non null value";
1681                     field public final String nullStringConstant;
1682                     field public String nonConstantString;
1683                   }
1684                 }
1685             """
1686                     .trimIndent()
1687             )
1688         ) {
1689             val fooClass = codebase.assertClass("test.pkg.Foo")
1690 
1691             val nonNullConstantType =
1692                 fooClass.fields().single { it.name() == "nonNullStringConstant" }.type()
1693             // Nullability not set through an annotation.
1694             nonNullConstantType.assertHasNonNullNullability(expectAnnotation = false)
1695 
1696             val nullConstantType =
1697                 fooClass.fields().single { it.name() == "nullStringConstant" }.type()
1698             nullConstantType.assertHasPlatformNullability()
1699 
1700             val nonConstantType =
1701                 fooClass.fields().single { it.name() == "nullStringConstant" }.type()
1702             nonConstantType.assertHasPlatformNullability()
1703         }
1704     }
1705 
1706     @Test
1707     fun `Test implicit nullability of constructor returns`() {
1708         runNullabilityTest(
1709             java(
1710                 """
1711                 package test.pkg;
1712                 public class Foo {}
1713             """
1714                     .trimIndent()
1715             ),
1716             signature(
1717                 """
1718                 // Signature format: 2.0
1719                 package test.pkg {
1720                   public class Foo {
1721                     ctor public Foo();
1722                   }
1723                 }
1724             """
1725                     .trimIndent()
1726             ),
1727             kotlin(
1728                 """
1729                 package test.pkg
1730                 class Foo
1731             """
1732                     .trimIndent()
1733             ),
1734             signature(
1735                 """
1736                 // Signature format: 5.0
1737                 package test.pkg {
1738                   public class Foo {
1739                     ctor public Foo();
1740                   }
1741                 }
1742             """
1743                     .trimIndent()
1744             )
1745         ) {
1746             val ctorReturn =
1747                 codebase.assertClass("test.pkg.Foo").constructors().single().returnType()
1748             // Constructor returns are always non-null without needing an annotation
1749             ctorReturn.assertHasNonNullNullability(expectAnnotation = false)
1750         }
1751     }
1752 
1753     @Test
1754     fun `Test implicit nullability of equals parameter`() {
1755         runCodebaseTest(
1756             java(
1757                 """
1758                     package test.pkg;
1759                     public class Foo {
1760                         @Override
1761                         public boolean equals(Object other) {}
1762                     }
1763                 """
1764                     .trimIndent()
1765             ),
1766             signature(
1767                 """
1768                     // Signature format: 5.0
1769                     // - kotlin-name-type-order=yes
1770                     // - include-type-use-annotations=yes
1771                     // - kotlin-style-nulls=no
1772                     package test.pkg {
1773                       public class Foo {
1774                         method public equals(other: Object): boolean;
1775                       }
1776                     }
1777                 """
1778                     .trimIndent()
1779             )
1780         ) {
1781             val equals = codebase.assertClass("test.pkg.Foo").methods().single()
1782             val objType = equals.parameters().single().type()
1783             // equals must accept null
1784             objType.assertHasNullableNullability(expectAnnotation = false)
1785         }
1786     }
1787 
1788     @Test
1789     fun `Test implicit nullability of toString`() {
1790         runCodebaseTest(
1791             java(
1792                 """
1793                     package test.pkg;
1794                     public class Foo {
1795                         @Override
1796                         public String toString() {}
1797                     }
1798                 """
1799                     .trimIndent()
1800             ),
1801             signature(
1802                 """
1803                     // Signature format: 5.0
1804                     // - kotlin-name-type-order=yes
1805                     // - include-type-use-annotations=yes
1806                     // - kotlin-style-nulls=no
1807                     package test.pkg {
1808                       public class Foo {
1809                         method public toString(): String;
1810                       }
1811                     }
1812                 """
1813                     .trimIndent()
1814             )
1815         ) {
1816             val strType = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1817             // toString must not return null
1818             strType.assertHasNonNullNullability(expectAnnotation = false)
1819         }
1820     }
1821 
1822     @Test
1823     fun `Test implicit nullability of annotation members`() {
1824         runCodebaseTest(
1825             java(
1826                 """
1827                     package test.pkg;
1828                     public @interface Foo {
1829                         String[] values();
1830                     }
1831                 """
1832                     .trimIndent()
1833             ),
1834             kotlin(
1835                 """
1836                     package test.pkg
1837                     annotation class Foo {
1838                         fun values(): Array<String>
1839                     }
1840                 """
1841                     .trimIndent()
1842             ),
1843             signature(
1844                 """
1845                     // Signature format: 5.0
1846                     // - kotlin-name-type-order=yes
1847                     // - include-type-use-annotations=yes
1848                     // - kotlin-style-nulls=no
1849                     package test.pkg {
1850                       public @interface Foo {
1851                         method public values(): String[];
1852                       }
1853                     }
1854                 """
1855                     .trimIndent()
1856             )
1857         ) {
1858             val strArray = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1859             strArray.assertArrayTypeItem {
1860                 assertHasNonNullNullability(expectAnnotation = false)
1861                 componentType.assertHasNonNullNullability(false)
1862             }
1863         }
1864     }
1865 
1866     @Test
1867     fun `Test nullness of Kotlin enum members`() {
1868         runCodebaseTest(
1869             kotlin(
1870                 """
1871                     package test.pkg
1872                     enum class Foo {
1873                         A
1874                     }
1875                 """
1876                     .trimIndent()
1877             )
1878         ) {
1879             val fooEnum = codebase.assertClass("test.pkg.Foo")
1880 
1881             // enum_constant public static final A: test.pkg.Foo;
1882             val enumConstant = fooEnum.fields().single()
1883             assertThat(enumConstant.isEnumConstant()).isTrue()
1884             enumConstant.type().assertHasNonNullNullability(expectAnnotation = false)
1885         }
1886     }
1887 
1888     @Test
1889     fun `Test nullness of companion object`() {
1890         runCodebaseTest(
1891             kotlin(
1892                 """
1893                     package test.pkg
1894                     class Foo {
1895                         companion object
1896                     }
1897                 """
1898                     .trimIndent()
1899             )
1900         ) {
1901             val fooClass = codebase.assertClass("test.pkg.Foo")
1902             val companionType = fooClass.fields().single().type()
1903             companionType.assertHasNonNullNullability(expectAnnotation = false)
1904         }
1905     }
1906 
1907     @Test
1908     fun `Test nullness of Kotlin lambda type`() {
1909         runCodebaseTest(
1910             kotlin(
1911                 """
1912                     package test.pkg
1913                     class Foo {
1914                         fun noParamToString(): () -> String {}
1915                         fun oneParamToString(): (String?) -> String {}
1916                         fun twoParamToString(): (String, Int?) -> String? {}
1917                         fun oneParamToUnit(): (String) -> Unit {}
1918                     }
1919                 """
1920                     .trimIndent()
1921             )
1922         ) {
1923             val fooClass = codebase.assertClass("test.pkg.Foo")
1924             // () -> String
1925             val noParamToString = fooClass.assertMethod("noParamToString", "").returnType()
1926             noParamToString.assertClassTypeItem {
1927                 assertHasNonNullNullability(expectAnnotation = false)
1928                 assertThat(arguments).hasSize(1)
1929                 arguments.single().assertHasNonNullNullability(expectAnnotation = false)
1930             }
1931 
1932             // (String?) -> String
1933             val oneParamToString = fooClass.assertMethod("oneParamToString", "").returnType()
1934             oneParamToString.assertClassTypeItem {
1935                 assertHasNonNullNullability(expectAnnotation = false)
1936                 assertThat(arguments).hasSize(2)
1937                 arguments[0].assertHasNullableNullability(expectAnnotation = false)
1938                 arguments[1].assertHasNonNullNullability(expectAnnotation = false)
1939             }
1940 
1941             // (String, Int?) -> String?
1942             val twoParamToString = fooClass.assertMethod("twoParamToString", "").returnType()
1943             twoParamToString.assertClassTypeItem {
1944                 assertHasNonNullNullability(expectAnnotation = false)
1945                 assertThat(arguments).hasSize(3)
1946                 arguments[0].assertHasNonNullNullability(expectAnnotation = false)
1947                 arguments[1].assertHasNullableNullability(expectAnnotation = false)
1948                 arguments[2].assertHasNullableNullability(expectAnnotation = false)
1949             }
1950 
1951             // (String) -> Unit
1952             val oneParamToUnit = fooClass.assertMethod("oneParamToUnit", "").returnType()
1953             oneParamToUnit.assertClassTypeItem {
1954                 assertHasNonNullNullability(expectAnnotation = false)
1955                 assertThat(arguments).hasSize(2)
1956                 arguments[0].assertHasNonNullNullability(expectAnnotation = false)
1957                 arguments[1].assertHasNonNullNullability(expectAnnotation = false)
1958             }
1959         }
1960     }
1961 
1962     @Test
1963     fun `Test inherited nullability of unbounded Kotlin type variables - usage is not null`() {
1964         runCodebaseTest(
1965             kotlin(
1966                 """
1967                     package test.pkg
1968                     class Foo<T> {
1969                         fun foo(): T {}
1970                     }
1971                 """
1972                     .trimIndent()
1973             )
1974         ) {
1975             // T is unbounded, so it has an implicit `Any?` bound, making it possibly nullable, but
1976             // not necessarily. That means the usage of the variable without any nullable suffix
1977             // doesn't have a nullability on its own, it depends on what type is used as the
1978             // parameter.
1979             val tVar = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
1980             tVar.assertHasUndefinedNullability()
1981         }
1982     }
1983 
1984     @Test
1985     fun `Test inherited nullability of unbounded Kotlin type variables - usage is nullable`() {
1986         runCodebaseTest(
1987             kotlin(
1988                 """
1989                     package test.pkg
1990                     class Foo<T> {
1991                         fun foo(): T? {}
1992                     }
1993                 """
1994                     .trimIndent()
1995             )
1996         ) {
1997             // T is unbounded, so it has an implicit `Any?` bound, making it possibly nullable, but
1998             // not necessarily. That means the usage of the variable without any nullable suffix
1999             // doesn't have a nullability on its own, it depends on what type is used as the
2000             // parameter. However, when it has a nullable suffix then it is nullable.
2001             val tVar = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
2002             tVar.assertHasNullableNullability()
2003         }
2004     }
2005 
2006     @Test
2007     fun `Test inherited nullability of bounded Kotlin type variables - bound is not nullable`() {
2008         runCodebaseTest(
2009             kotlin(
2010                 """
2011                     package test.pkg
2012                     class Foo<T : Any> {
2013                         fun foo(): T {}
2014                     }
2015                 """
2016                     .trimIndent()
2017             )
2018         ) {
2019             // T is bounded by `Any` so it cannot be nullable which means that the variable on its
2020             // own is not nullable.
2021             val tVar = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
2022             tVar.assertHasNonNullNullability()
2023         }
2024     }
2025 
2026     @Test
2027     fun `Test inherited nullability of bounded Kotlin type variables - bound is nullable`() {
2028         runCodebaseTest(
2029             kotlin(
2030                 """
2031                     package test.pkg
2032                     class Foo<T : Number?> {
2033                         fun foo(): T {}
2034                     }
2035                 """
2036                     .trimIndent()
2037             )
2038         ) {
2039             // T is bounded by `Number?`, making it possibly nullable, but not necessarily. That
2040             // means the usage of the variable without any nullable suffix doesn't have a
2041             // nullability on its own, it depends on what type is used as the parameter.
2042             val tVar = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
2043             tVar.assertHasUndefinedNullability()
2044         }
2045     }
2046 
2047     @Test
2048     fun `Test nullability of Kotlin properties and accessors`() {
2049         runCodebaseTest(
2050             kotlin(
2051                 """
2052                     package test.pkg
2053                     class Foo {
2054                         var nullableString: String?
2055                         var nonNullListNullableString: List<String?>
2056                     }
2057                 """
2058                     .trimIndent()
2059             )
2060         ) {
2061             val fooClass = codebase.assertClass("test.pkg.Foo")
2062 
2063             val nullableStringProp = fooClass.properties().single { it.name() == "nullableString" }
2064             nullableStringProp.type().assertHasNullableNullability(expectAnnotation = false)
2065             nullableStringProp.getter!!
2066                 .returnType()
2067                 .assertHasNullableNullability(expectAnnotation = false)
2068             nullableStringProp.setter!!
2069                 .parameters()
2070                 .single()
2071                 .type()
2072                 .assertHasNullableNullability(expectAnnotation = false)
2073 
2074             val nonNullListProp =
2075                 fooClass.properties().single { it.name() == "nonNullListNullableString" }
2076             val propType = nonNullListProp.type()
2077             val getterType = nonNullListProp.getter!!.returnType()
2078             val setterType = nonNullListProp.setter!!.parameters().single().type()
2079             propType.assertClassTypeItem {
2080                 assertHasNonNullNullability(expectAnnotation = false)
2081                 arguments.single().assertHasNullableNullability(expectAnnotation = false)
2082             }
2083             getterType.assertClassTypeItem {
2084                 assertHasNonNullNullability(expectAnnotation = false)
2085                 arguments.single().assertHasNullableNullability(expectAnnotation = false)
2086             }
2087             setterType.assertClassTypeItem {
2088                 assertHasNonNullNullability(expectAnnotation = false)
2089                 arguments.single().assertHasNullableNullability(expectAnnotation = false)
2090             }
2091         }
2092     }
2093 
2094     @Test
2095     fun `Test nullability of extension function type`() {
2096         runCodebaseTest(
2097             kotlin(
2098                 """
2099                     package test.pkg
2100                     class Foo {
2101                         fun foo(): String?.(Int, Int?) -> String {}
2102                     }
2103                 """
2104                     .trimIndent()
2105             )
2106         ) {
2107             val extensionFunctionType =
2108                 codebase.assertClass("test.pkg.Foo").methods().single().returnType()
2109             extensionFunctionType.assertClassTypeItem {
2110                 assertHasNonNullNullability(expectAnnotation = false)
2111                 val receiverType = arguments[0]
2112                 receiverType.assertHasNullableNullability(expectAnnotation = false)
2113                 val typeArgument1 = arguments[1]
2114                 typeArgument1.assertHasNonNullNullability(expectAnnotation = false)
2115                 val typeArgument2 = arguments[2]
2116                 typeArgument2.assertHasNullableNullability(expectAnnotation = false)
2117                 val returnType = arguments[3]
2118                 returnType.assertHasNonNullNullability(expectAnnotation = false)
2119             }
2120         }
2121     }
2122 
2123     @Test
2124     fun `Test nullability of typealias`() {
2125         runCodebaseTest(
2126             kotlin(
2127                 """
2128                     package test.pkg
2129                     class Foo {
2130                         fun foo(): FunctionType?
2131                     }
2132                     typealias FunctionType = (String) -> Int?
2133                 """
2134                     .trimIndent()
2135             )
2136         ) {
2137             val functionType = codebase.assertClass("test.pkg.Foo").methods().single().returnType()
2138             functionType.assertClassTypeItem {
2139                 assertHasNullableNullability(expectAnnotation = false)
2140                 val typeArgument = arguments[0]
2141                 typeArgument.assertHasNonNullNullability(expectAnnotation = false)
2142                 val returnType = arguments[1]
2143                 returnType.assertHasNullableNullability(expectAnnotation = false)
2144             }
2145         }
2146     }
2147 
2148     @Test
2149     fun `Test nullability of super class type`() {
2150         runCodebaseTest(
2151             java(
2152                 """
2153                     package test.pkg;
2154                     public class Foo extends Number {}
2155                 """
2156             ),
2157             kotlin(
2158                 """
2159                     package test.pkg
2160                     class Foo: Number {
2161                     }
2162                 """
2163             ),
2164             signature(
2165                 """
2166                     // Signature format: 2.0
2167                     package test.pkg {
2168                       public class Foo extends Number {
2169                       }
2170                     }
2171                 """
2172             ),
2173         ) {
2174             val superClassType = codebase.assertClass("test.pkg.Foo").superClassType()!!
2175             superClassType.assertHasNonNullNullability(expectAnnotation = false)
2176         }
2177     }
2178 
2179     @Test
2180     fun `Test nullability of super interface type`() {
2181         runCodebaseTest(
2182             java(
2183                 """
2184                     package test.pkg;
2185                     import java.util.Map;
2186                     public abstract class Foo implements Map.Entry<String, String> {}
2187                 """
2188             ),
2189             kotlin(
2190                 """
2191                     package test.pkg
2192                     import java.util.Map
2193                     abstract class Foo: Map.Entry<String, String> {
2194                     }
2195                 """
2196             ),
2197             signature(
2198                 """
2199                     // Signature format: 2.0
2200                     package test.pkg {
2201                       public abstract class Foo implements java.util.Map.Entry<java.lang.String, java.lang.String> {
2202                       }
2203                     }
2204                 """
2205             ),
2206         ) {
2207             val superInterfaceType = codebase.assertClass("test.pkg.Foo").interfaceTypes().single()
2208 
2209             // The outer class type must be non-null.
2210             val outerClassType = superInterfaceType.outerClassType!!
2211             outerClassType.assertHasNonNullNullability(expectAnnotation = false)
2212 
2213             // As must the nested class.
2214             superInterfaceType.assertHasNonNullNullability(expectAnnotation = false)
2215         }
2216     }
2217 
2218     @Test
2219     fun `Test nullability of generic super class and interface type`() {
2220         runCodebaseTest(
2221             java(
2222                 """
2223                     package test.pkg;
2224                     import java.util.List;
2225                     public abstract class Foo<E> extends Number implements List<E> {}
2226                 """
2227             ),
2228             kotlin(
2229                 """
2230                     package test.pkg
2231                     import java.util.List
2232                     abstract class Foo<E>: List<E> {
2233                     }
2234                 """
2235             ),
2236             signature(
2237                 """
2238                     // Signature format: 2.0
2239                     package test.pkg {
2240                       public abstract class Foo<E> extends Number implements java.util.List<E> {
2241                       }
2242                     }
2243                 """
2244             ),
2245         ) {
2246             val fooClass = codebase.assertClass("test.pkg.Foo")
2247 
2248             // The super class type must be non-null.
2249             val superClassType = codebase.assertClass("test.pkg.Foo").superClassType()!!
2250             superClassType.assertHasNonNullNullability(expectAnnotation = false)
2251 
2252             // The super interface types must be non-null.
2253             val superInterfaceType = fooClass.interfaceTypes().single()
2254             superInterfaceType.assertHasNonNullNullability(expectAnnotation = false)
2255         }
2256     }
2257 
2258     @Test
2259     fun `Test nullability of class type parameter from constructor`() {
2260         runCodebaseTest(
2261             java(
2262                 """
2263                     package test.pkg;
2264                     public class Foo<F> {
2265                         public class Bar<B> {}
2266                     }
2267                 """
2268                     .trimIndent()
2269             ),
2270             kotlin(
2271                 """
2272                     package test.pkg
2273                     class Foo<F> {
2274                         inner class Bar<B>
2275                     }
2276                 """
2277                     .trimIndent()
2278             ),
2279             signature(
2280                 """
2281                     // Signature format: 5.0
2282                     package test.pkg {
2283                       public class Foo<F> {
2284                         ctor public Foo();
2285                       }
2286                       public class Foo.Bar<B> {
2287                         ctor public Foo.Bar();
2288                       }
2289                     }
2290                 """
2291                     .trimIndent()
2292             ),
2293         ) {
2294             val foo = codebase.assertClass("test.pkg.Foo").constructors().single().returnType()
2295             foo.assertHasNonNullNullability()
2296             val f = (foo as ClassTypeItem).arguments.single()
2297             f.assertHasUndefinedNullability()
2298 
2299             val bar = codebase.assertClass("test.pkg.Foo.Bar").constructors().single().returnType()
2300             bar.assertHasNonNullNullability()
2301             val b = (bar as ClassTypeItem).arguments.single()
2302             b.assertHasUndefinedNullability()
2303             val outerFoo = bar.outerClassType!!
2304             outerFoo.assertHasNonNullNullability()
2305             val outerF = outerFoo.arguments.single()
2306             outerF.assertHasUndefinedNullability()
2307         }
2308     }
2309 
2310     @Test
2311     fun `Test nullness of unbounded kotlin wildcard`() {
2312         runCodebaseTest(
2313             kotlin(
2314                 """
2315                     package test.pkg
2316                     class Foo {
2317                         fun foo(): List<*>
2318                     }
2319                 """
2320                     .trimIndent()
2321             )
2322         ) {
2323             val fooMethod = codebase.assertClass("test.pkg.Foo").methods().single()
2324             val wildcardType = (fooMethod.returnType() as ClassTypeItem).arguments.single()
2325 
2326             wildcardType.assertHasUndefinedNullability()
2327             wildcardType.assertWildcardItem {
2328                 extendsBound.assertNotNullTypeItem { assertHasNullableNullability() }
2329             }
2330         }
2331     }
2332 }
2333