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