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.ArrayTypeItem 20 import com.android.tools.metalava.model.BaseTypeTransformer 21 import com.android.tools.metalava.model.ClassItem 22 import com.android.tools.metalava.model.ClassTypeItem 23 import com.android.tools.metalava.model.MethodItem 24 import com.android.tools.metalava.model.PrimitiveTypeItem 25 import com.android.tools.metalava.model.ReferenceTypeItem 26 import com.android.tools.metalava.model.TypeArgumentTypeItem 27 import com.android.tools.metalava.model.TypeItem 28 import com.android.tools.metalava.model.TypeModifiers 29 import com.android.tools.metalava.model.VariableTypeItem 30 import com.android.tools.metalava.model.WildcardTypeItem 31 import com.android.tools.metalava.model.provider.InputFormat 32 import com.android.tools.metalava.model.testing.testTypeString 33 import com.android.tools.metalava.model.testsuite.BaseModelTest 34 import com.android.tools.metalava.testing.KnownSourceFiles 35 import com.android.tools.metalava.testing.java 36 import com.android.tools.metalava.testing.kotlin 37 import com.google.common.truth.Truth.assertThat 38 import com.google.common.truth.Truth.assertWithMessage 39 import kotlin.test.assertEquals 40 import org.junit.Test 41 42 class CommonTypeItemTest : BaseModelTest() { 43 @Test 44 fun `Test primitive types`() { 45 runCodebaseTest( 46 java( 47 """ 48 package test.pkg; 49 public class Foo { 50 public void foo( 51 boolean p0, 52 byte p1, 53 char p2, 54 double p3, 55 float p4, 56 int p5, 57 long p6, 58 short p7 59 ) {} 60 } 61 """ 62 ), 63 kotlin( 64 """ 65 package test.pkg 66 class Foo { 67 fun foo( 68 p0: Boolean, 69 p1: Byte, 70 p2: Char, 71 p3: Double, 72 p4: Float, 73 p5: Int, 74 p6: Long, 75 p7: Short 76 ) = Unit 77 } 78 """ 79 ), 80 signature( 81 """ 82 // Signature format: 4.0 83 package test.pkg { 84 public class Foo { 85 ctor public Foo(); 86 method public void foo(boolean, byte, char, double, float, int, long, short); 87 } 88 } 89 """ 90 .trimIndent() 91 ) 92 ) { 93 val method = codebase.assertClass("test.pkg.Foo").methods().single() 94 95 val returnType = method.returnType() 96 assertThat(returnType).isInstanceOf(PrimitiveTypeItem::class.java) 97 assertThat((returnType as PrimitiveTypeItem).kind) 98 .isEqualTo(PrimitiveTypeItem.Primitive.VOID) 99 100 val expectedParamTypes = 101 listOf( 102 PrimitiveTypeItem.Primitive.BOOLEAN, 103 PrimitiveTypeItem.Primitive.BYTE, 104 PrimitiveTypeItem.Primitive.CHAR, 105 PrimitiveTypeItem.Primitive.DOUBLE, 106 PrimitiveTypeItem.Primitive.FLOAT, 107 PrimitiveTypeItem.Primitive.INT, 108 PrimitiveTypeItem.Primitive.LONG, 109 PrimitiveTypeItem.Primitive.SHORT 110 ) 111 112 val params = method.parameters().map { it.type() } 113 assertThat(params).hasSize(expectedParamTypes.size) 114 for ((param, expectedKind) in params.zip(expectedParamTypes)) { 115 assertThat(param).isInstanceOf(PrimitiveTypeItem::class.java) 116 assertThat((param as PrimitiveTypeItem).kind).isEqualTo(expectedKind) 117 } 118 } 119 } 120 121 @Test 122 fun `Test primitive array types`() { 123 runCodebaseTest( 124 java( 125 """ 126 package test.pkg; 127 public class Foo { 128 public void foo( 129 int[] p0, 130 char[] p1 131 ) {} 132 } 133 """ 134 ), 135 // The Kotlin equivalent can be interpreted with java.lang types instead of primitives 136 signature( 137 """ 138 // Signature format: 4.0 139 package test.pkg { 140 public class Foo { 141 ctor public Foo(); 142 method public void foo(int[], char[]); 143 } 144 } 145 """ 146 .trimIndent() 147 ) 148 ) { 149 val method = codebase.assertClass("test.pkg.Foo").methods().single() 150 151 val paramTypes = method.parameters().map { it.type() } 152 assertThat(paramTypes).hasSize(2) 153 154 // int[] 155 val intArray = paramTypes[0] 156 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 157 val int = (intArray as ArrayTypeItem).componentType 158 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 159 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 160 assertThat(intArray.isVarargs).isFalse() 161 162 // char[] 163 val charArray = paramTypes[1] 164 assertThat(charArray).isInstanceOf(ArrayTypeItem::class.java) 165 val char = (charArray as ArrayTypeItem).componentType 166 assertThat(char).isInstanceOf(PrimitiveTypeItem::class.java) 167 assertThat((char as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.CHAR) 168 assertThat(charArray.isVarargs).isFalse() 169 } 170 } 171 172 @Test 173 fun `Test primitive vararg types`() { 174 runCodebaseTest( 175 java( 176 """ 177 package test.pkg; 178 public class Foo { 179 public void foo(int... p0) {} 180 } 181 """ 182 ), 183 kotlin( 184 """ 185 package test.pkg 186 class Foo { 187 fun foo(vararg p0: Int 188 ) = Unit 189 } 190 """ 191 ), 192 signature( 193 """ 194 // Signature format: 4.0 195 package test.pkg { 196 public class Foo { 197 ctor public Foo(); 198 method public void foo(int...); 199 } 200 } 201 """ 202 .trimIndent() 203 ) 204 ) { 205 val method = codebase.assertClass("test.pkg.Foo").methods().single() 206 207 val paramTypes = method.parameters().map { it.type() } 208 assertThat(paramTypes).hasSize(1) 209 210 // int... / vararg int 211 val intArray = paramTypes[0] 212 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 213 val int = (intArray as ArrayTypeItem).componentType 214 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 215 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 216 assertThat(intArray.isVarargs).isTrue() 217 } 218 } 219 220 @Test 221 fun `Test multidimensional primitive array types`() { 222 runCodebaseTest( 223 java( 224 """ 225 package test.pkg; 226 public class Foo { 227 public void foo( 228 int[][] p0, 229 char[]... p1 230 ) {} 231 } 232 """ 233 ), 234 // The Kotlin equivalent can be interpreted with java.lang types instead of primitives 235 signature( 236 """ 237 // Signature format: 4.0 238 package test.pkg { 239 public class Foo { 240 ctor public Foo(); 241 method public void foo(int[][], char[]...); 242 } 243 } 244 """ 245 .trimIndent() 246 ) 247 ) { 248 val method = codebase.assertClass("test.pkg.Foo").methods().single() 249 250 val paramTypes = method.parameters().map { it.type() } 251 assertThat(paramTypes).hasSize(2) 252 253 // int[][] 254 val intArrayArray = paramTypes[0] 255 assertThat(intArrayArray).isInstanceOf(ArrayTypeItem::class.java) 256 assertThat((intArrayArray as ArrayTypeItem).isVarargs).isFalse() 257 258 val intArray = intArrayArray.componentType 259 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 260 assertThat((intArray as ArrayTypeItem).isVarargs).isFalse() 261 262 val int = intArray.componentType 263 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 264 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 265 266 // char[]... 267 val charArrayArray = paramTypes[1] 268 assertThat(charArrayArray).isInstanceOf(ArrayTypeItem::class.java) 269 assertThat((charArrayArray as ArrayTypeItem).isVarargs).isTrue() 270 271 val charArray = charArrayArray.componentType 272 assertThat(charArray).isInstanceOf(ArrayTypeItem::class.java) 273 assertThat((charArray as ArrayTypeItem).isVarargs).isFalse() 274 275 val char = charArray.componentType 276 assertThat(char).isInstanceOf(PrimitiveTypeItem::class.java) 277 assertThat((char as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.CHAR) 278 } 279 } 280 281 @Test 282 fun `Test class array types`() { 283 runCodebaseTest( 284 java( 285 """ 286 package test.pkg; 287 public class Foo { 288 public void foo( 289 java.lang.String[] p0, 290 java.lang.String[][] p1, 291 java.lang.String... p2 292 ) {} 293 } 294 """ 295 ), 296 kotlin( 297 """ 298 package test.pkg 299 class Foo { 300 fun foo( 301 p0: Array<String>, 302 p1: Array<Array<String>>, 303 vararg p2: String 304 ) = Unit 305 } 306 """ 307 ), 308 signature( 309 """ 310 // Signature format: 4.0 311 package test.pkg { 312 public class Foo { 313 ctor public Foo(); 314 method public void foo(String![]!, String![]![]!, java.lang.String!...); 315 } 316 } 317 """ 318 .trimIndent() 319 ) 320 ) { 321 val method = codebase.assertClass("test.pkg.Foo").methods().single() 322 323 val paramTypes = method.parameters().map { it.type() } 324 assertThat(paramTypes).hasSize(3) 325 326 // String[] / Array<String> 327 val simpleArray = paramTypes[0] 328 assertThat(simpleArray).isInstanceOf(ArrayTypeItem::class.java) 329 assertThat((simpleArray as ArrayTypeItem).componentType.isString()).isTrue() 330 assertThat(simpleArray.isVarargs).isFalse() 331 332 // String[][] / Array<Array<String>> 333 val twoDimensionalArray = paramTypes[1] 334 assertThat(twoDimensionalArray).isInstanceOf(ArrayTypeItem::class.java) 335 assertThat((twoDimensionalArray as ArrayTypeItem).isVarargs).isFalse() 336 val innerArray = twoDimensionalArray.componentType 337 assertThat(innerArray).isInstanceOf(ArrayTypeItem::class.java) 338 assertThat((innerArray as ArrayTypeItem).componentType.isString()).isTrue() 339 assertThat(innerArray.isVarargs).isFalse() 340 341 // String... / vararg String 342 val varargs = paramTypes[2] 343 assertThat(twoDimensionalArray).isInstanceOf(ArrayTypeItem::class.java) 344 assertThat((varargs as ArrayTypeItem).componentType.isString()).isTrue() 345 assertThat(varargs.isVarargs).isTrue() 346 } 347 } 348 349 @Test 350 fun `Test wildcard types`() { 351 runCodebaseTest( 352 java( 353 """ 354 package test.pkg; 355 public class Foo<T> { 356 public void foo( 357 Foo<?> p0, 358 Foo<? extends java.lang.String> p1, 359 Foo<? super java.lang.String> p2, 360 Foo<? extends java.lang.String[]> p3 361 ) {} 362 } 363 """ 364 ), 365 kotlin( 366 """ 367 package test.pkg 368 class Foo<T> { 369 fun foo( 370 p0: Foo<*>, 371 p1: Foo<out String>, 372 p2: Foo<in String>, 373 p3: Foo<out Array<String>> 374 ) = Unit 375 } 376 """ 377 ), 378 signature( 379 """ 380 // Signature format: 4.0 381 package test.pkg { 382 public class Foo<T> { 383 ctor public Foo(); 384 method public void foo(test.pkg.Foo<?>!, test.pkg.Foo<? extends java.lang.String>!, test.pkg.Foo<? super java.lang.String>!, test.pkg.Foo<? extends java.lang.String[]>!); 385 } 386 } 387 """ 388 .trimIndent() 389 ) 390 ) { 391 val method = codebase.assertClass("test.pkg.Foo").methods().single() 392 393 val wildcardTypes = 394 method.parameters().map { 395 val paramType = it.type() 396 assertThat(paramType).isInstanceOf(ClassTypeItem::class.java) 397 assertThat((paramType as ClassTypeItem).arguments).hasSize(1) 398 paramType.arguments.single() 399 } 400 assertThat(wildcardTypes).hasSize(4) 401 402 // Foo<?> / Foo<*> 403 // Unbounded wildcards implicitly have an Object extends bound 404 val unboundedWildcard = wildcardTypes[0] 405 assertThat(unboundedWildcard).isInstanceOf(WildcardTypeItem::class.java) 406 val unboundedExtendsBound = (unboundedWildcard as WildcardTypeItem).extendsBound 407 assertThat(unboundedExtendsBound).isNotNull() 408 assertThat(unboundedExtendsBound!!.isJavaLangObject()).isTrue() 409 assertThat(unboundedWildcard.superBound).isNull() 410 411 // Foo<? extends String> / Foo<out String> 412 val extendsBoundWildcard = wildcardTypes[1] 413 assertThat(extendsBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 414 val extendsBound = (extendsBoundWildcard as WildcardTypeItem).extendsBound 415 assertThat(extendsBound).isNotNull() 416 assertThat(extendsBound!!.isString()).isTrue() 417 assertThat(extendsBoundWildcard.superBound).isNull() 418 419 // Foo<? super String> / Foo<in String> 420 // A super bounded wildcard implicitly has an Object extends bound 421 val superBoundWildcard = wildcardTypes[2] 422 assertThat(superBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 423 val superExtendsBound = (superBoundWildcard as WildcardTypeItem).extendsBound 424 assertThat(superExtendsBound).isNotNull() 425 assertThat(superExtendsBound!!.isJavaLangObject()).isTrue() 426 val superBound = superBoundWildcard.superBound 427 assertThat(superBound).isNotNull() 428 assertThat(superBound!!.isString()).isTrue() 429 430 // Foo<? extends java.lang.String[]> / Foo<in Array<String>> 431 val arrayExtendsBoundWildcard = wildcardTypes[3] 432 assertThat(arrayExtendsBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 433 val arrayExtendsBound = (arrayExtendsBoundWildcard as WildcardTypeItem).extendsBound 434 assertThat(arrayExtendsBound).isNotNull() 435 assertThat(arrayExtendsBound).isInstanceOf(ArrayTypeItem::class.java) 436 assertThat((arrayExtendsBound as ArrayTypeItem).componentType.isString()).isTrue() 437 } 438 } 439 440 @Test 441 fun `Test variable types`() { 442 runCodebaseTest( 443 java( 444 """ 445 package test.pkg; 446 public class Foo<C> { 447 public <M> void foo(C p0, M p1) {} 448 } 449 """ 450 ), 451 kotlin( 452 """ 453 package test.pkg 454 class Foo<C> { 455 fun <M> foo(p0: C, p1: M) = Unit 456 } 457 """ 458 ), 459 signature( 460 """ 461 // Signature format: 4.0 462 package test.pkg { 463 public class Foo<C> { 464 ctor public Foo(); 465 method public <M> void foo(C!, M!); 466 } 467 } 468 """ 469 .trimIndent() 470 ) 471 ) { 472 val clz = codebase.assertClass("test.pkg.Foo") 473 val classTypeParam = clz.typeParameterList.single() 474 val method = clz.methods().single() 475 val methodTypeParam = method.typeParameterList.single() 476 val paramTypes = method.parameters().map { it.type() } 477 assertThat(paramTypes).hasSize(2) 478 479 val classTypeVariable = paramTypes[0] 480 classTypeVariable.assertReferencesTypeParameter(classTypeParam) 481 assertThat((classTypeVariable as VariableTypeItem).name).isEqualTo("C") 482 483 val methodTypeVariable = paramTypes[1] 484 methodTypeVariable.assertReferencesTypeParameter(methodTypeParam) 485 assertThat((methodTypeVariable as VariableTypeItem).name).isEqualTo("M") 486 } 487 } 488 489 @Test 490 fun `Test method return type variable types`() { 491 runCodebaseTest( 492 java( 493 """ 494 package test.pkg; 495 public class Foo<T> { 496 public T bar1() {} 497 public <A extends java.lang.String> A bar2() {} 498 public <A extends java.lang.String> T bar3() {} 499 public <T extends java.lang.String> T bar4() {} 500 } 501 """ 502 ), 503 kotlin( 504 """ 505 package test.pkg 506 class Foo<T> { 507 fun bar1(): T {} 508 fun <A: java.lang.String> bar2(): A {} 509 fun <A: java.lang.String> bar3(): T {} 510 fun <T: java.lang.String> bar4(): T {} 511 } 512 """ 513 ), 514 signature( 515 """ 516 // Signature format: 4.0 517 package test.pkg { 518 public class Foo<T> { 519 method public T bar1(); 520 method public <A extends java.lang.String> A bar2(); 521 method public <A extends java.lang.String> T bar3(); 522 method public <T extends java.lang.String> T bar4(); 523 } 524 } 525 """ 526 .trimIndent() 527 ) 528 ) { 529 val foo = codebase.assertClass("test.pkg.Foo") 530 val fooTypeParam = foo.typeParameterList.single() 531 532 val bar1 = foo.methods().single { it.name() == "bar1" } 533 val bar1Return = bar1.returnType() 534 bar1Return.assertReferencesTypeParameter(fooTypeParam) 535 536 val bar2 = foo.methods().single { it.name() == "bar2" } 537 val bar2TypeParam = bar2.typeParameterList.single() 538 val bar2Return = bar2.returnType() 539 bar2Return.assertReferencesTypeParameter(bar2TypeParam) 540 541 val bar3 = foo.methods().single { it.name() == "bar3" } 542 val bar3Return = bar3.returnType() 543 bar3Return.assertReferencesTypeParameter(fooTypeParam) 544 545 val bar4 = foo.methods().single { it.name() == "bar4" } 546 val bar4TypeParam = bar4.typeParameterList.single() 547 val bar4Return = bar4.returnType() 548 bar4Return.assertReferencesTypeParameter(bar4TypeParam) 549 } 550 } 551 552 @Test 553 fun `Test method parameter type variable types`() { 554 runCodebaseTest( 555 java( 556 """ 557 package test.pkg; 558 public class Foo<T> { 559 public void bar1(T p0) {} 560 public <A extends java.lang.String> void bar2(A p0) {} 561 public <A extends java.lang.String> void bar3(T p0) {} 562 public <T extends java.lang.String> void bar4(T p0) {} 563 } 564 """ 565 ), 566 kotlin( 567 """ 568 package test.pkg 569 class Foo<T> { 570 fun bar1(p0: T) = Unit 571 fun <A: java.lang.String> bar2(p0: A) = Unit 572 fun <A: java.lang.String> bar3(p0: T) = Unit 573 fun <T: java.lang.String> bar4(p0: T) = Unit 574 } 575 """ 576 ), 577 signature( 578 """ 579 // Signature format: 4.0 580 package test.pkg { 581 public class Foo<T> { 582 method public void bar1(T p); 583 method public <A extends java.lang.String> void bar2(A p); 584 method public <A extends java.lang.String> void bar3(T p); 585 method public <T extends java.lang.String> void bar4(T p); 586 } 587 } 588 """ 589 .trimIndent() 590 ) 591 ) { 592 val foo = codebase.assertClass("test.pkg.Foo") 593 val fooParam = foo.typeParameterList.single() 594 595 val bar1 = foo.methods().single { it.name() == "bar1" } 596 val bar1Param = bar1.parameters().single().type() 597 bar1Param.assertReferencesTypeParameter(fooParam) 598 599 val bar2 = foo.methods().single { it.name() == "bar2" } 600 val bar2TypeParam = bar2.typeParameterList.single() 601 val bar2Param = bar2.parameters().single().type() 602 bar2Param.assertReferencesTypeParameter(bar2TypeParam) 603 604 val bar3 = foo.methods().single { it.name() == "bar3" } 605 val bar3Param = bar3.parameters().single().type() 606 bar3Param.assertReferencesTypeParameter(fooParam) 607 608 val bar4 = foo.methods().single { it.name() == "bar4" } 609 val bar4TypeParam = bar4.typeParameterList.single() 610 val bar4Param = bar4.parameters().single().type() 611 bar4Param.assertReferencesTypeParameter(bar4TypeParam) 612 } 613 } 614 615 @Test 616 fun `Test field type variable types`() { 617 runCodebaseTest( 618 java( 619 """ 620 package test.pkg; 621 public class Foo<T> { 622 public T foo; 623 } 624 """ 625 .trimIndent() 626 ), 627 kotlin( 628 """ 629 package test.pkg 630 class Foo<T> { 631 @JvmField val foo: T 632 } 633 """ 634 ), 635 signature( 636 """ 637 // Signature format: 4.0 638 package test.pkg { 639 public class Foo<T> { 640 field public T foo; 641 } 642 } 643 """ 644 .trimIndent() 645 ) 646 ) { 647 val foo = codebase.assertClass("test.pkg.Foo") 648 val fooParam = foo.typeParameterList.single() 649 650 val fieldType = foo.fields().single { it.name() == "foo" }.type() 651 fieldType.assertReferencesTypeParameter(fooParam) 652 } 653 } 654 655 @Test 656 fun `Test property type variable types`() { 657 runCodebaseTest( 658 // No java equivalent 659 kotlin( 660 """ 661 package test.pkg 662 class Foo<T> { 663 val foo: T 664 } 665 """ 666 .trimIndent() 667 ), 668 signature( 669 """ 670 // Signature format: 4.0 671 package test.pkg { 672 public class Foo<T> { 673 property public T foo; 674 } 675 } 676 """ 677 .trimIndent() 678 ) 679 ) { 680 val foo = codebase.assertClass("test.pkg.Foo") 681 val fooParam = foo.typeParameterList.single() 682 683 val propertyType = foo.properties().single { it.name() == "foo" }.type() 684 propertyType.assertReferencesTypeParameter(fooParam) 685 } 686 } 687 688 @Test 689 fun `Test class types`() { 690 runCodebaseTest( 691 java( 692 """ 693 package test.pkg; 694 public class Foo { 695 public <T> void foo( 696 java.lang.String p0, 697 java.util.List<java.lang.String> p1, 698 java.util.List<java.lang.String[]> p2, 699 java.util.Map<java.lang.String, Foo> p3 700 ) {} 701 } 702 """ 703 ), 704 kotlin( 705 """ 706 package test.pkg 707 class Foo { 708 fun <T> foo( 709 p0: String, 710 p1: List<String>, 711 p2: List<Array<String>>, 712 p3: Map<String, Foo> 713 ) = Unit 714 } 715 """ 716 ), 717 signature( 718 """ 719 // Signature format: 4.0 720 package test.pkg { 721 public class Foo { 722 ctor public Foo(); 723 method public <T> void foo(String!, java.util.List<java.lang.String!>!, java.util.List<java.lang.String![]!>!, java.util.Map<java.lang.String!,test.pkg.Foo!>!); 724 } 725 } 726 """ 727 .trimIndent() 728 ) 729 ) { 730 val method = codebase.assertClass("test.pkg.Foo").methods().single() 731 val paramTypes = method.parameters().map { it.type() } 732 733 val stringType = paramTypes[0] 734 assertThat(stringType).isInstanceOf(ClassTypeItem::class.java) 735 assertThat((stringType as ClassTypeItem).qualifiedName).isEqualTo("java.lang.String") 736 assertThat(stringType.className).isEqualTo("String") 737 assertThat(stringType.arguments).isEmpty() 738 739 // List<String> 740 val stringListType = paramTypes[1] 741 assertThat(stringListType).isInstanceOf(ClassTypeItem::class.java) 742 assertThat((stringListType as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 743 assertThat(stringListType.className).isEqualTo("List") 744 assertThat(stringListType.arguments).hasSize(1) 745 assertThat(stringListType.arguments.single().isString()).isTrue() 746 747 // List<String[]> / List<Array<String>> 748 val arrayListType = paramTypes[2] 749 assertThat(arrayListType).isInstanceOf(ClassTypeItem::class.java) 750 assertThat((arrayListType as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 751 assertThat(arrayListType.arguments).hasSize(1) 752 val arrayType = arrayListType.arguments.single() 753 assertThat(arrayType).isInstanceOf(ArrayTypeItem::class.java) 754 assertThat((arrayType as ArrayTypeItem).componentType.isString()).isTrue() 755 756 // Map<String, Foo> 757 val mapType = paramTypes[3] 758 assertThat(mapType).isInstanceOf(ClassTypeItem::class.java) 759 assertThat((mapType as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map") 760 assertThat(mapType.arguments).hasSize(2) 761 val mapKeyType = mapType.arguments.first() 762 assertThat(mapKeyType).isInstanceOf(ClassTypeItem::class.java) 763 assertThat((mapKeyType as ClassTypeItem).isString()).isTrue() 764 val mapValueType = mapType.arguments.last() 765 assertThat(mapValueType).isInstanceOf(ClassTypeItem::class.java) 766 assertThat((mapValueType as ClassTypeItem).qualifiedName).isEqualTo("test.pkg.Foo") 767 } 768 } 769 770 @Test 771 fun `Test inner types`() { 772 runCodebaseTest( 773 java( 774 """ 775 package test.pkg; 776 public class Outer { 777 public class Middle { 778 public class Inner {} 779 } 780 781 public Outer.Middle.Inner foo() { 782 return new Outer.Middle.Inner(); 783 } 784 } 785 """ 786 ), 787 kotlin( 788 """ 789 package test.pkg 790 class Outer { 791 inner class Middle { 792 inner class Inner 793 } 794 795 fun foo(): Outer.Middle.Inner { 796 return Outer.Middle.Inner() 797 } 798 } 799 """ 800 ), 801 signature( 802 """ 803 // Signature format: 4.0 804 package test.pkg { 805 public class Outer { 806 ctor public Outer(); 807 method public test.pkg.Outer.Middle.Inner foo(); 808 } 809 public class Outer.Middle { 810 ctor public Outer.Middle(); 811 } 812 public class Outer.Middle.Inner { 813 ctor public Outer.Middle.Inner(); 814 } 815 } 816 """ 817 .trimIndent() 818 ) 819 ) { 820 val method = codebase.assertClass("test.pkg.Outer").methods().single() 821 822 // Outer.Middle.Inner 823 val innerType = method.returnType() 824 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 825 assertThat((innerType as ClassTypeItem).qualifiedName) 826 .isEqualTo("test.pkg.Outer.Middle.Inner") 827 assertThat(innerType.className).isEqualTo("Inner") 828 assertThat(innerType.arguments).isEmpty() 829 830 val middleType = innerType.outerClassType 831 assertThat(middleType).isNotNull() 832 assertThat(middleType!!.qualifiedName).isEqualTo("test.pkg.Outer.Middle") 833 assertThat(middleType.className).isEqualTo("Middle") 834 assertThat(middleType.arguments).isEmpty() 835 836 val outerType = middleType.outerClassType 837 assertThat(outerType).isNotNull() 838 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg.Outer") 839 assertThat(outerType.className).isEqualTo("Outer") 840 assertThat(outerType.arguments).isEmpty() 841 assertThat(outerType.outerClassType).isNull() 842 } 843 } 844 845 @Test 846 fun `Test inner types from classpath`() { 847 runCodebaseTest( 848 java( 849 """ 850 package test.pkg; 851 852 import java.util.Map; 853 854 public class Test { 855 public Map.Entry<String,String> foo() { 856 return new Map.Entry<String,String>(); 857 } 858 } 859 """ 860 ), 861 kotlin( 862 """ 863 package test.pkg 864 865 import java.util.Map 866 867 class Test { 868 fun foo(): Map.Entry<String,String> { 869 return Map.Entry<String,String>() 870 } 871 } 872 """ 873 ), 874 signature( 875 """ 876 // Signature format: 4.0 877 package test.pkg { 878 public class Test { 879 ctor public Outer(); 880 method public java.util.Map.Entry<java.lang.String,java.lang.String> foo(); 881 } 882 } 883 """ 884 .trimIndent() 885 ) 886 ) { 887 val method = codebase.assertClass("test.pkg.Test").methods().single() 888 889 // Map.Entry<String,String> 890 val innerType = method.returnType() 891 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 892 assertThat((innerType as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map.Entry") 893 assertThat(innerType.className).isEqualTo("Entry") 894 895 val outerType = innerType.outerClassType 896 assertThat(outerType).isNotNull() 897 assertThat(outerType!!.qualifiedName).isEqualTo("java.util.Map") 898 assertThat(outerType.className).isEqualTo("Map") 899 assertThat(outerType.arguments).hasSize(0) 900 assertThat(outerType.outerClassType).isNull() 901 } 902 } 903 904 @Test 905 fun `Test inner parameterized types`() { 906 runCodebaseTest( 907 java( 908 """ 909 package test.pkg; 910 public class Outer<O> { 911 public class Inner<I> { 912 } 913 914 public <P1, P2> Outer<P1>.Inner<P2> foo() { 915 return new Outer<P1>.Inner<P2>(); 916 } 917 } 918 """ 919 ), 920 kotlin( 921 """ 922 package test.pkg 923 class Outer<O> { 924 inner class Inner<I> 925 926 fun <P1, P2> foo(): Outer<P1>.Inner<P2> { 927 return Outer<P1>.Inner<P2>() 928 } 929 } 930 """ 931 ), 932 signature( 933 """ 934 // Signature format: 4.0 935 package test.pkg { 936 public class Outer<O> { 937 ctor public Outer(); 938 method public <P1, P2> test.pkg.Outer<P1!>.Inner<P2!>! foo(); 939 } 940 public class Outer.Inner<I> { 941 ctor public Outer.Inner(); 942 } 943 } 944 """ 945 .trimIndent() 946 ) 947 ) { 948 val method = codebase.assertClass("test.pkg.Outer").methods().single() 949 val methodTypeParameters = method.typeParameterList 950 assertThat(methodTypeParameters).hasSize(2) 951 val p1 = methodTypeParameters[0] 952 val p2 = methodTypeParameters[1] 953 954 // Outer<P1>.Inner<P2> 955 val innerType = method.returnType() 956 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 957 assertThat((innerType as ClassTypeItem).qualifiedName).isEqualTo("test.pkg.Outer.Inner") 958 assertThat(innerType.className).isEqualTo("Inner") 959 assertThat(innerType.arguments).hasSize(1) 960 val innerTypeArgument = innerType.arguments.single() 961 innerTypeArgument.assertReferencesTypeParameter(p2) 962 assertThat((innerTypeArgument as VariableTypeItem).name).isEqualTo("P2") 963 964 val outerType = innerType.outerClassType 965 assertThat(outerType).isNotNull() 966 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg.Outer") 967 assertThat(outerType.className).isEqualTo("Outer") 968 assertThat(outerType.outerClassType).isNull() 969 assertThat(outerType.arguments).hasSize(1) 970 val outerClassTypeArgument = outerType.arguments.single() 971 outerClassTypeArgument.assertReferencesTypeParameter(p1) 972 assertThat((outerClassTypeArgument as VariableTypeItem).name).isEqualTo("P1") 973 } 974 } 975 976 @Test 977 fun `Test inner parameterized types without explicit outer type`() { 978 runCodebaseTest( 979 inputSet( 980 java( 981 """ 982 package test.pkg; 983 984 import test.pkg1.Outer.Middle.Inner; 985 986 public class Test { 987 public Inner<String> foo() { 988 return new Inner<String>(); 989 } 990 } 991 """ 992 ), 993 java( 994 """ 995 package test.pkg1; 996 997 public class Outer<O> { 998 public class Middle { 999 public class Inner<I> {} 1000 } 1001 } 1002 """ 1003 ), 1004 ), 1005 inputSet( 1006 signature( 1007 "api1.txt", 1008 """ 1009 // Signature format: 4.0 1010 package test.pkg1 { 1011 public class Outer<O> { 1012 ctor public Outer(); 1013 } 1014 public class Outer.Middle { 1015 ctor public Outer.Middle(); 1016 } 1017 public class Outer.Middle.Inner<I> { 1018 ctor public Outer.Middle.Inner(); 1019 } 1020 } 1021 """ 1022 ), 1023 signature( 1024 "api2.txt", 1025 """ 1026 // Signature format: 4.0 1027 package test.pkg { 1028 public class Test { 1029 ctor public Test(); 1030 method public test.pkg1.Outer.Middle.Inner<String> foo(); 1031 } 1032 } 1033 """ 1034 ) 1035 ) 1036 ) { 1037 val method = codebase.assertClass("test.pkg.Test").methods().single() 1038 1039 val innerType = method.returnType() 1040 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 1041 assertThat((innerType as ClassTypeItem).qualifiedName) 1042 .isEqualTo("test.pkg1.Outer.Middle.Inner") 1043 assertThat(innerType.className).isEqualTo("Inner") 1044 assertThat(innerType.arguments).hasSize(1) 1045 1046 val middleType = innerType.outerClassType 1047 assertThat(middleType).isNotNull() 1048 assertThat(middleType!!.qualifiedName).isEqualTo("test.pkg1.Outer.Middle") 1049 assertThat(middleType.className).isEqualTo("Middle") 1050 assertThat(middleType.arguments).hasSize(0) 1051 1052 val outerType = middleType.outerClassType 1053 assertThat(outerType).isNotNull() 1054 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg1.Outer") 1055 assertThat(outerType.className).isEqualTo("Outer") 1056 assertThat(outerType.outerClassType).isNull() 1057 assertThat(outerType.arguments).hasSize(0) 1058 } 1059 } 1060 1061 @Test 1062 fun `Test superclass and interface types using type variables`() { 1063 runCodebaseTest( 1064 java( 1065 """ 1066 package test.pkg; 1067 1068 public class Cache<Query, Result> extends java.util.HashMap<Query,Result> {} 1069 1070 public class MyList<E> implements java.util.List<E> {} 1071 """ 1072 .trimIndent() 1073 ), 1074 kotlin( 1075 """ 1076 package test.pkg 1077 1078 class Cache<Query, Result> : java.util.HashMap<Query, Result> 1079 1080 class MyList<E> : java.util.List<E> 1081 """ 1082 .trimIndent() 1083 ), 1084 signature( 1085 """ 1086 // Signature format: 2.0 1087 package test.pkg { 1088 public class Cache<Query, Result> extends java.util.HashMap<Query,Result> { 1089 } 1090 public class MyList<E> implements java.util.List<E> { 1091 } 1092 } 1093 """ 1094 .trimIndent() 1095 ) 1096 ) { 1097 // Verify that the Cache superclass type uses the Cache type variables 1098 val cache = codebase.assertClass("test.pkg.Cache") 1099 val cacheTypeParams = cache.typeParameterList 1100 assertThat(cacheTypeParams).hasSize(2) 1101 val queryParam = cacheTypeParams[0] 1102 val resultParam = cacheTypeParams[1] 1103 1104 val cacheSuperclassType = cache.superClassType() 1105 assertThat(cacheSuperclassType).isInstanceOf(ClassTypeItem::class.java) 1106 assertThat((cacheSuperclassType as ClassTypeItem).qualifiedName) 1107 .isEqualTo("java.util.HashMap") 1108 assertThat(cacheSuperclassType.arguments).hasSize(2) 1109 1110 val queryVar = cacheSuperclassType.arguments[0] 1111 queryVar.assertReferencesTypeParameter(queryParam) 1112 1113 val resultVar = cacheSuperclassType.arguments[1] 1114 resultVar.assertReferencesTypeParameter(resultParam) 1115 1116 // Verify that the MyList interface type uses the MyList type variable 1117 val myList = codebase.assertClass("test.pkg.MyList") 1118 val myListTypeParams = myList.typeParameterList 1119 assertThat(myListTypeParams).hasSize(1) 1120 val eParam = myListTypeParams.single() 1121 1122 val myListInterfaces = myList.interfaceTypes() 1123 assertThat(myListInterfaces).hasSize(1) 1124 1125 val myListInterfaceType = myListInterfaces.single() 1126 assertThat(myListInterfaceType).isInstanceOf(ClassTypeItem::class.java) 1127 assertThat(myListInterfaceType.qualifiedName).isEqualTo("java.util.List") 1128 assertThat(myListInterfaceType.arguments).hasSize(1) 1129 1130 val eVar = myListInterfaceType.arguments.single() 1131 eVar.assertReferencesTypeParameter(eParam) 1132 } 1133 } 1134 1135 @Test 1136 fun `Test array of type with parameter used as type parameter`() { 1137 runCodebaseTest( 1138 signature( 1139 """ 1140 // Signature format: 2.0 1141 package test.pkg { 1142 public class Foo { 1143 method public java.util.Collection<java.util.List<java.lang.String>[]> foo(); 1144 } 1145 } 1146 """ 1147 .trimIndent() 1148 ), 1149 java( 1150 """ 1151 package test.pkg; 1152 1153 import java.util.Collection; 1154 import java.util.List; 1155 1156 public class Foo { 1157 public Collection<List<String>[]> foo() {} 1158 } 1159 """, 1160 ), 1161 kotlin( 1162 """ 1163 package test.pkg 1164 1165 class Foo { 1166 fun foo(): Collection<Array<List<String>>> {} 1167 } 1168 """ 1169 ) 1170 ) { 1171 val method = codebase.assertClass("test.pkg.Foo").methods().single() 1172 1173 // java.util.Collection<java.util.List<java.lang.String>[]> 1174 val collectionOfArrayOfStringList = method.returnType() 1175 assertThat(collectionOfArrayOfStringList).isInstanceOf(ClassTypeItem::class.java) 1176 assertThat((collectionOfArrayOfStringList as ClassTypeItem).qualifiedName) 1177 .isEqualTo("java.util.Collection") 1178 assertThat(collectionOfArrayOfStringList.arguments).hasSize(1) 1179 1180 // java.util.List<java.lang.String>[] 1181 val arrayOfStringList = collectionOfArrayOfStringList.arguments.single() 1182 assertThat(arrayOfStringList).isInstanceOf(ArrayTypeItem::class.java) 1183 1184 // java.util.List<java.lang.String> 1185 val stringList = (arrayOfStringList as ArrayTypeItem).componentType 1186 assertThat(stringList).isInstanceOf(ClassTypeItem::class.java) 1187 assertThat((stringList as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 1188 assertThat(stringList.arguments).hasSize(1) 1189 1190 // java.lang.String 1191 val string = stringList.arguments.single() 1192 assertThat(string.isString()).isTrue() 1193 } 1194 } 1195 1196 @Test 1197 fun `Test Kotlin collection removeAll parameter type`() { 1198 runCodebaseTest( 1199 kotlin( 1200 """ 1201 package test.pkg 1202 abstract class Foo<Z> : MutableCollection<Z> { 1203 override fun addAll(elements: Collection<Z>): Boolean = true 1204 override fun containsAll(elements: Collection<Z>): Boolean = true 1205 override fun removeAll(elements: Collection<Z>): Boolean = true 1206 override fun retainAll(elements: Collection<Z>): Boolean = true 1207 } 1208 """ 1209 ) 1210 ) { 1211 val fooClass = codebase.assertClass("test.pkg.Foo") 1212 val typeParam = fooClass.typeParameterList.single() 1213 1214 /** 1215 * Make sure that the [ClassItem] has a method whose single parameter is of the type 1216 * `java.lang.Collection` and then run [body] on that type. 1217 */ 1218 fun ClassItem.assertMethodTakesCollection( 1219 name: String, 1220 body: TypeArgumentTypeItem.() -> Unit 1221 ) { 1222 val method = methods().single { it.name() == name } 1223 val paramType = method.parameters().single().type() 1224 paramType.assertClassTypeItem { 1225 assertThat(qualifiedName).isEqualTo("java.util.Collection") 1226 assertThat(arguments).hasSize(1) 1227 val argument = arguments.single() 1228 argument.body() 1229 } 1230 } 1231 1232 /** 1233 * Make sure that the [ClassItem] has a method whose single parameter is of the type 1234 * `java.lang.Collection<? extends Z>`. 1235 */ 1236 fun ClassItem.assertMethodTakesCollectionWildcardExtendsZ(name: String) { 1237 assertMethodTakesCollection(name) { 1238 assertWildcardItem { extendsBound!!.assertReferencesTypeParameter(typeParam) } 1239 } 1240 } 1241 1242 // Defined in `java.util.Collection` as `addAll(Collection<? extends E> c)`. The type of 1243 // the `addAll` method in `Foo` should be `addAll(Collection<? extends Z>)`.Where `Z` 1244 // references the type parameter in `Foo<Z>`. 1245 fooClass.assertMethodTakesCollectionWildcardExtendsZ("addAll") 1246 1247 // Defined in `java.util.Collection` as `...(Collection<?> c)` these methods should be 1248 // `...(Collection<? extends Z>)`.Where `Z` references the type parameter in 1249 // `Foo<Z>`. 1250 // 1251 fooClass.assertMethodTakesCollectionWildcardExtendsZ("containsAll") 1252 fooClass.assertMethodTakesCollectionWildcardExtendsZ("removeAll") 1253 fooClass.assertMethodTakesCollectionWildcardExtendsZ("retainAll") 1254 } 1255 } 1256 1257 @Test 1258 fun `Test convertType`() { 1259 runCodebaseTest( 1260 inputSet( 1261 java( 1262 """ 1263 package test.pkg; 1264 import java.util.List; 1265 import java.util.Map; 1266 public class Parent<M, N> { 1267 public M getM() {} 1268 public N[] getNArray() {} 1269 public List<M> getMList() {} 1270 public Map<M, N> getMap() {} 1271 public Parent<? extends M, ? super N> getWildcards() {} 1272 } 1273 """ 1274 .trimIndent() 1275 ), 1276 java( 1277 """ 1278 package test.pkg; 1279 public class Child<X, Y> extends Parent<X, Y> {} 1280 """ 1281 .trimIndent() 1282 ), 1283 ), 1284 inputSet( 1285 signature( 1286 """ 1287 // Signature format: 5.0 1288 package test.pkg { 1289 public class Child<X, Y> extends test.pkg.Parent<X,Y> { 1290 } 1291 public class Parent<M, N> { 1292 method public M getM(); 1293 method public java.util.List<M> getMList(); 1294 method public java.util.Map<M,N> getMap(); 1295 method public N[] getNArray(); 1296 method public test.pkg.Parent<? extends M, ? super N> getWildcards(); 1297 } 1298 } 1299 """ 1300 .trimIndent() 1301 ) 1302 ), 1303 inputSet( 1304 kotlin( 1305 """ 1306 package test.pkg 1307 open class Parent<M, N> { 1308 fun getM(): M {} 1309 fun getNArray(): Array<N> {} 1310 fun getMList(): List<M> {} 1311 fun getMap(): Map<M, N> {} 1312 fun getWildcards(): Parent<out M, in N> {} 1313 } 1314 class Child<X, Y> : Parent<X, Y>() 1315 """ 1316 .trimIndent() 1317 ) 1318 ) 1319 ) { 1320 val parent = codebase.assertClass("test.pkg.Parent") 1321 val child = codebase.assertClass("test.pkg.Child") 1322 val childTypeParams = child.typeParameterList 1323 val x = childTypeParams[0] 1324 val y = childTypeParams[1] 1325 1326 val mVar = parent.assertMethod("getM", "").returnType() 1327 val xVar = mVar.convertType(child, parent) 1328 assertThat(xVar.toTypeString()).isEqualTo("X") 1329 xVar.assertReferencesTypeParameter(x) 1330 1331 val nArray = parent.assertMethod("getNArray", "").returnType() 1332 val yArray = nArray.convertType(child, parent) 1333 assertThat(yArray.toTypeString()).isEqualTo("Y[]") 1334 assertThat((yArray as ArrayTypeItem).isVarargs).isFalse() 1335 yArray.componentType.assertReferencesTypeParameter(y) 1336 1337 val mList = parent.assertMethod("getMList", "").returnType() 1338 val xList = mList.convertType(child, parent) 1339 assertThat(xList.toTypeString()).isEqualTo("java.util.List<X>") 1340 assertThat((xList as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 1341 xList.arguments.single().assertReferencesTypeParameter(x) 1342 1343 val mToNMap = parent.assertMethod("getMap", "").returnType() 1344 val xToYMap = mToNMap.convertType(child, parent) 1345 assertThat(xToYMap.toTypeString()).isEqualTo("java.util.Map<X,Y>") 1346 assertThat((xToYMap as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map") 1347 xToYMap.arguments[0].assertReferencesTypeParameter(x) 1348 xToYMap.arguments[1].assertReferencesTypeParameter(y) 1349 1350 val wildcards = parent.assertMethod("getWildcards", "").returnType() 1351 val convertedWildcards = wildcards.convertType(child, parent) 1352 assertThat(convertedWildcards.toTypeString()) 1353 .isEqualTo("test.pkg.Parent<? extends X,? super Y>") 1354 assertThat((convertedWildcards as ClassTypeItem).qualifiedName) 1355 .isEqualTo("test.pkg.Parent") 1356 assertThat(convertedWildcards.arguments).hasSize(2) 1357 1358 val extendsX = convertedWildcards.arguments[0] as WildcardTypeItem 1359 extendsX.extendsBound!!.assertReferencesTypeParameter(x) 1360 val superN = convertedWildcards.arguments[1] as WildcardTypeItem 1361 superN.superBound!!.assertReferencesTypeParameter(y) 1362 } 1363 } 1364 1365 @Test 1366 fun `Test convertType with maps`() { 1367 runCodebaseTest( 1368 java( 1369 """ 1370 package test.pkg; 1371 import java.util.List; 1372 public class Foo<T, X> { 1373 public Number numberType; 1374 1375 public int primitiveType; 1376 public int primitiveTypeAfterMatchingConversion; 1377 1378 public T variableType; 1379 public Number variableTypeAfterMatchingConversion; 1380 1381 public T[] arrayType; 1382 public Number[] arrayTypeAfterMatchingConversion; 1383 1384 public Foo<T, String> classType; 1385 public Foo<Number, String> classTypeAfterMatchingConversion; 1386 1387 public Foo<? extends T, String> wildcardExtendsType; 1388 public Foo<? extends Number, String> wildcardExtendsTypeAfterMatchingConversion; 1389 1390 public Foo<? super T, String> wildcardSuperType; 1391 public Foo<? super Number, String> wildcardSuperTypeAfterMatchingConversion; 1392 } 1393 """ 1394 .trimIndent() 1395 ), 1396 kotlin( 1397 """ 1398 package test.pkg 1399 class Foo<T, X> { 1400 @JvmField val numberType: Number 1401 1402 @JvmField val primitiveType: Int 1403 @JvmField val primitiveTypeAfterMatchingConversion: Int 1404 1405 @JvmField val variableType: T 1406 @JvmField val variableTypeAfterMatchingConversion: Number 1407 1408 @JvmField val arrayType: Array<T> 1409 @JvmField val arrayTypeAfterMatchingConversion: Array<Number> 1410 1411 @JvmField val classType: Foo<T, String> 1412 @JvmField val classTypeAfterMatchingConversion: Foo<Number, String> 1413 1414 @JvmField val wildcardExtendsType: Foo<out T, String> 1415 @JvmField val wildcardExtendsTypeAfterMatchingConversion: Foo<out Number, String> 1416 1417 @JvmField val wildcardSuperType: Foo<in T, String> 1418 @JvmField val wildcardSuperTypeAfterMatchingConversion: Foo<in Number, String> 1419 } 1420 """ 1421 .trimIndent() 1422 ), 1423 signature( 1424 """ 1425 // Signature format: 5.0 1426 package test.pkg { 1427 public class Foo<T, X> { 1428 field public Number numberType; 1429 1430 field public int primitiveType; 1431 field public int primitiveTypeAfterMatchingConversion; 1432 1433 field public T variableType; 1434 field public Number variableTypeAfterMatchingConversion; 1435 1436 field public T[] arrayType; 1437 field public Number[] arrayTypeAfterMatchingConversion; 1438 1439 field public test.pkg.Foo<T, String> classType; 1440 field public test.pkg.Foo<Number, String> classTypeAfterMatchingConversion; 1441 1442 field public test.pkg.Foo<? extends T, String> wildcardExtendsType; 1443 field public test.pkg.Foo<? extends Number, String> wildcardExtendsTypeAfterMatchingConversion; 1444 1445 field public test.pkg.Foo<? super T, String> wildcardSuperType; 1446 field public test.pkg.Foo<? super Number, String> wildcardSuperTypeAfterMatchingConversion; 1447 } 1448 } 1449 """ 1450 .trimIndent() 1451 ) 1452 ) { 1453 val fooClass = codebase.assertClass("test.pkg.Foo") 1454 val t = fooClass.typeParameterList.single { it.name() == "T" } 1455 val x = fooClass.typeParameterList.single { it.name() == "X" } 1456 val numberType = fooClass.assertField("numberType").type() as ReferenceTypeItem 1457 1458 val matchingBindings = mapOf(t to numberType) 1459 val nonMatchingBindings = mapOf(x to numberType) 1460 1461 val afterMatchingConversionSuffix = "AfterMatchingConversion" 1462 val fieldsToCheck = 1463 fooClass.fields().filter { 1464 it.name() != "numberType" && !it.name().endsWith(afterMatchingConversionSuffix) 1465 } 1466 1467 for (fieldItem in fieldsToCheck) { 1468 val fieldType = fieldItem.type() 1469 1470 val fieldName = fieldItem.name() 1471 val expectedMatchedFieldType = 1472 fooClass.assertField(fieldName + afterMatchingConversionSuffix).type() 1473 1474 assertWithMessage("conversion that matches $fieldName") 1475 .that(fieldType.convertType(matchingBindings)) 1476 .isEqualTo(expectedMatchedFieldType) 1477 1478 // Expect no change if it does not match. 1479 assertWithMessage("conversion that does not match $fieldName") 1480 .that(fieldType.convertType(nonMatchingBindings)) 1481 .isEqualTo(fieldType) 1482 } 1483 } 1484 } 1485 1486 @Test 1487 fun `Test convertType's creation of duplicate objects`() { 1488 runCodebaseTest( 1489 inputSet( 1490 signature( 1491 """ 1492 // Signature format: 2.0 1493 package test.pkg { 1494 public interface Input<T,Unused> { 1495 // Field from which the type to be substituted for a type variable will 1496 // be retrieved. 1497 field public @NonNull Long javaLongType; 1498 1499 // One for each TypeItem subinterface supported in signature files. 1500 method public @NonNull T @Nullable [] arrayTypeItem(); 1501 method public @Nullable java.util.List<@NonNull T> classTypeItem(); 1502 method public int primitiveTypeItem(); 1503 method public @Nullable T variableTypeItem(); 1504 method public @Nullable java.util.List<? extends @NonNull T> wildcardTypeItem_extendsBound(); 1505 method public @Nullable java.util.List<? super @NonNull T> wildcardTypeItem_superBound(); 1506 } 1507 } 1508 """ 1509 ), 1510 ), 1511 inputSet( 1512 KnownSourceFiles.nonNullSource, 1513 KnownSourceFiles.nullableSource, 1514 java( 1515 """ 1516 package test.pkg; 1517 import android.annotation.NonNull; 1518 import android.annotation.Nullable; 1519 import java.util.List; 1520 public interface Input<T,Unused> { 1521 // Field from which the type to be substituted for a type variable will 1522 // be retrieved. 1523 @NonNull Long javaLongType; 1524 1525 // One for each TypeItem subinterface supported in signature files. 1526 @NonNull T @Nullable [] arrayTypeItem(); 1527 @Nullable List<@NonNull T> classTypeItem(); 1528 int primitiveTypeItem(); 1529 @Nullable T variableTypeItem(); 1530 @Nullable List<? extends @NonNull T> wildcardTypeItem_extendsBound(); 1531 @Nullable List<? super @NonNull T> wildcardTypeItem_superBound(); 1532 } 1533 """ 1534 ), 1535 ), 1536 inputSet( 1537 kotlin( 1538 """ 1539 package test.pkg 1540 import java.util.List 1541 interface Input<T,Unused> { 1542 // Field from which the type to be substituted for a type variable will 1543 // be retrieved. 1544 companion object { 1545 @JvmField val javaLongType: java.lang.Long 1546 } 1547 1548 // One for each TypeItem subinterface supported in signature files. 1549 fun arrayTypeItem(): Array<T>? 1550 fun classTypeItem(): List<T>? 1551 fun lambdaTypeItem(): ((T) -> Int)? 1552 fun primitiveTypeItem(): Int 1553 fun variableTypeItem(): T? 1554 fun wildcardTypeItem_extendsBound(): List<out T>? 1555 fun wildcardTypeItem_superBound(): List<in T>? 1556 } 1557 """ 1558 ), 1559 ), 1560 ) { 1561 val inputClass = codebase.assertClass("test.pkg.Input") 1562 1563 // Get the type variables from the class. 1564 val (usedTypeVariable, unusedTypeVariable) = inputClass.typeParameterList 1565 1566 // Get the type to substitute 1567 val javaLongType = inputClass.assertField("javaLongType").type() as ReferenceTypeItem 1568 1569 // Iterate over the methods 1570 val types = buildString { 1571 for (method in inputClass.methods()) { 1572 val name = method.name() 1573 val typeToTest = method.returnType() 1574 1575 fun TypeItem.typeInfo() = 1576 testTypeString( 1577 annotations = true, 1578 kotlinStyleNulls = true, 1579 ) 1580 1581 append(name).append("\n") 1582 append(" original: ${typeToTest.typeInfo()}\n") 1583 1584 // Map the Unused type variable to java.lang.Long. This should have no effect of 1585 // on the test type. 1586 typeToTest.convertType(mapOf(unusedTypeVariable to javaLongType)).also { result 1587 -> 1588 append("${" no change"}: ${result.typeInfo()}\n") 1589 val unusedMessage = 1590 "conversion of ${unusedTypeVariable.name()} to $javaLongType in $name" 1591 assertWithMessage(unusedMessage).that(result).isSameInstanceAs(typeToTest) 1592 } 1593 1594 // Map the T type variable to java.lang.Long. This should change every type 1595 // except the primitive type. 1596 typeToTest.convertType(mapOf(usedTypeVariable to javaLongType)).also { result -> 1597 append("${" T -> java.lang.Long"}: ${result.typeInfo()}\n") 1598 val usedMessage = 1599 "conversion of ${usedTypeVariable.name()} to $javaLongType in $name" 1600 if (name == "primitiveTypeItem") { 1601 assertWithMessage(usedMessage).that(result).isSameInstanceAs(typeToTest) 1602 } else { 1603 assertWithMessage(usedMessage) 1604 .that(result) 1605 .isNotSameInstanceAs(typeToTest) 1606 } 1607 } 1608 1609 append("\n") 1610 } 1611 } 1612 1613 val optionalLambda = 1614 """ 1615 lambdaTypeItem 1616 original: kotlin.jvm.functions.Function1<T,java.lang.Integer>? 1617 no change: kotlin.jvm.functions.Function1<T,java.lang.Integer>? 1618 T -> java.lang.Long: kotlin.jvm.functions.Function1<java.lang.Long,java.lang.Integer>? 1619 """ 1620 1621 assertEquals( 1622 """ 1623 arrayTypeItem 1624 original: T[]? 1625 no change: T[]? 1626 T -> java.lang.Long: java.lang.Long[]? 1627 1628 classTypeItem 1629 original: java.util.List<T>? 1630 no change: java.util.List<T>? 1631 T -> java.lang.Long: java.util.List<java.lang.Long>? 1632 ${if (inputFormat == InputFormat.KOTLIN) optionalLambda else ""} 1633 primitiveTypeItem 1634 original: int 1635 no change: int 1636 T -> java.lang.Long: int 1637 1638 variableTypeItem 1639 original: T? 1640 no change: T? 1641 T -> java.lang.Long: java.lang.Long? 1642 1643 wildcardTypeItem_extendsBound 1644 original: java.util.List<? extends T>? 1645 no change: java.util.List<? extends T>? 1646 T -> java.lang.Long: java.util.List<? extends java.lang.Long>? 1647 1648 wildcardTypeItem_superBound 1649 original: java.util.List<? super T>? 1650 no change: java.util.List<? super T>? 1651 T -> java.lang.Long: java.util.List<? super java.lang.Long>? 1652 """ 1653 .trimIndent(), 1654 types.trim() 1655 ) 1656 } 1657 } 1658 1659 @Test 1660 fun `Test transform's creation of duplicate objects`() { 1661 val typeUseAnnotation = 1662 java( 1663 """ 1664 package test.annotation; 1665 import java.lang.annotation.ElementType; 1666 import java.lang.annotation.Target; 1667 1668 @Target(ElementType.TYPE_USE) 1669 public @interface TypeUse {} 1670 """ 1671 ) 1672 runCodebaseTest( 1673 inputSet( 1674 signature( 1675 """ 1676 // Signature format: 5.0 1677 // - kotlin-style-nulls=yes 1678 // - kotlin-name-type-order=yes 1679 // - include-type-use-annotations=yes 1680 package test.pkg { 1681 public interface Input<T> { 1682 // One for each TypeItem subinterface supported in signature files. 1683 method public arrayTypeItem(): T @test.annotation.TypeUse []?; 1684 method public classTypeItem(): @test.annotation.TypeUse java.util.List<@test.annotation.TypeUse T>?; 1685 method public primitiveTypeItem(): @test.annotation.TypeUse int; 1686 method public variableTypeItem(): @test.annotation.TypeUse T?; 1687 method public wildcardTypeItem_extendsBound(): java.util.List<? extends @test.annotation.TypeUse T>?; 1688 method public wildcardTypeItem_superBound(): java.util.List<? super @test.annotation.TypeUse T>?; 1689 } 1690 } 1691 package test.annotation { 1692 public @interface TypeUse { 1693 } 1694 } 1695 """ 1696 ), 1697 ), 1698 inputSet( 1699 KnownSourceFiles.nonNullSource, 1700 KnownSourceFiles.nullableSource, 1701 typeUseAnnotation, 1702 java( 1703 """ 1704 package test.pkg; 1705 import android.annotation.NonNull; 1706 import android.annotation.Nullable; 1707 import java.util.List; 1708 import test.annotation.TypeUse; 1709 public interface Input<T,Unused> { 1710 @NonNull T @TypeUse @Nullable [] arrayTypeItem(); 1711 @TypeUse @Nullable List<@TypeUse @NonNull T> classTypeItem(); 1712 @TypeUse int primitiveTypeItem(); 1713 @TypeUse @Nullable T variableTypeItem(); 1714 @Nullable List<? extends @TypeUse @NonNull T> wildcardTypeItem_extendsBound(); 1715 @Nullable List<? super @TypeUse @NonNull T> wildcardTypeItem_superBound(); 1716 } 1717 """ 1718 ), 1719 ), 1720 inputSet( 1721 typeUseAnnotation, 1722 kotlin( 1723 """ 1724 package test.pkg 1725 import java.util.List 1726 import test.annotation.TypeUse 1727 interface Input<T,Unused> { 1728 fun arrayTypeItem(): @TypeUse Array<T>? 1729 fun classTypeItem(): @TypeUse List<@TypeUse T>? 1730 fun lambdaTypeItem(): ((@TypeUse T) -> @TypeUse Int)? 1731 fun primitiveTypeItem(): @TypeUse Int 1732 fun variableTypeItem(): @TypeUse T? 1733 fun wildcardTypeItem_extendsBound(): List<out @TypeUse T>? 1734 fun wildcardTypeItem_superBound(): List<in @TypeUse T>? 1735 } 1736 """ 1737 ), 1738 ), 1739 ) { 1740 val inputClass = codebase.assertClass("test.pkg.Input") 1741 1742 // Iterate over the methods 1743 val types = buildString { 1744 for (method in inputClass.methods()) { 1745 val name = method.name() 1746 val typeToTest = method.returnType() 1747 1748 fun TypeItem.typeInfo() = 1749 testTypeString( 1750 annotations = true, 1751 kotlinStyleNulls = true, 1752 ) 1753 1754 append(name).append("\n") 1755 append(" original: ${typeToTest.typeInfo()}\n") 1756 1757 // Check that a no-op transformation returns the TypeItem on which it is called. 1758 typeToTest.transform(BaseTypeTransformer()).also { result -> 1759 append("${" no change"}: ${result.typeInfo()}\n") 1760 val unusedMessage = "no-op transformation in $name" 1761 assertWithMessage(unusedMessage).that(result).isSameInstanceAs(typeToTest) 1762 } 1763 1764 // A TypeTransformer that will discard all type annotations. 1765 val annotationsRemover = 1766 object : BaseTypeTransformer() { 1767 override fun transform(modifiers: TypeModifiers): TypeModifiers { 1768 return modifiers.substitute(annotations = emptyList()) 1769 } 1770 } 1771 1772 // Check that an actual transformation returns different objects. 1773 typeToTest.transform(annotationsRemover).also { result -> 1774 append(" discarded annotations: ${result.typeInfo()}\n") 1775 val usedMessage = "discarded annotations in $name" 1776 assertWithMessage(usedMessage).that(result).isNotSameInstanceAs(typeToTest) 1777 } 1778 1779 append("\n") 1780 } 1781 } 1782 1783 val optionalLambda = 1784 """ 1785 lambdaTypeItem 1786 original: kotlin.jvm.functions.Function1<@test.annotation.TypeUse T,java.lang.@test.annotation.TypeUse Integer>? 1787 no change: kotlin.jvm.functions.Function1<@test.annotation.TypeUse T,java.lang.@test.annotation.TypeUse Integer>? 1788 discarded annotations: kotlin.jvm.functions.Function1<T,java.lang.Integer>? 1789 """ 1790 1791 assertEquals( 1792 """ 1793 arrayTypeItem 1794 original: T @test.annotation.TypeUse []? 1795 no change: T @test.annotation.TypeUse []? 1796 discarded annotations: T[]? 1797 1798 classTypeItem 1799 original: java.util.@test.annotation.TypeUse List<@test.annotation.TypeUse T>? 1800 no change: java.util.@test.annotation.TypeUse List<@test.annotation.TypeUse T>? 1801 discarded annotations: java.util.List<T>? 1802 ${if (inputFormat == InputFormat.KOTLIN) optionalLambda else ""} 1803 primitiveTypeItem 1804 original: @test.annotation.TypeUse int 1805 no change: @test.annotation.TypeUse int 1806 discarded annotations: int 1807 1808 variableTypeItem 1809 original: @test.annotation.TypeUse T? 1810 no change: @test.annotation.TypeUse T? 1811 discarded annotations: T? 1812 1813 wildcardTypeItem_extendsBound 1814 original: java.util.List<? extends @test.annotation.TypeUse T>? 1815 no change: java.util.List<? extends @test.annotation.TypeUse T>? 1816 discarded annotations: java.util.List<? extends T>? 1817 1818 wildcardTypeItem_superBound 1819 original: java.util.List<? super @test.annotation.TypeUse T>? 1820 no change: java.util.List<? super @test.annotation.TypeUse T>? 1821 discarded annotations: java.util.List<? super T>? 1822 """ 1823 .trimIndent(), 1824 types.trim() 1825 ) 1826 } 1827 } 1828 1829 @Test 1830 fun `Test hasTypeArguments`() { 1831 runCodebaseTest( 1832 java( 1833 """ 1834 package test.pkg; 1835 public abstract class Foo implements Comparable<String> {} 1836 """ 1837 ), 1838 kotlin( 1839 """ 1840 package test.pkg 1841 abstract class Foo: Comparable<String> 1842 """ 1843 ), 1844 signature( 1845 """ 1846 // Signature format: 2.0 1847 package test.pkg { 1848 public abstract class Foo implements Comparable<String> {} 1849 } 1850 """ 1851 ), 1852 ) { 1853 val classType = codebase.assertClass("test.pkg.Foo").type() 1854 assertThat(classType.hasTypeArguments()).isFalse() 1855 1856 val interfaceType = codebase.assertClass("test.pkg.Foo").interfaceTypes().single() 1857 assertThat(interfaceType.hasTypeArguments()).isTrue() 1858 } 1859 } 1860 1861 @Test 1862 fun `Test toSimpleType on varargs parameter`() { 1863 runCodebaseTest( 1864 java( 1865 """ 1866 package test.pkg; 1867 public interface Foo { 1868 void foo(String...p); 1869 } 1870 """ 1871 ), 1872 kotlin( 1873 """ 1874 package test.pkg 1875 interface Foo { 1876 fun foo(vararg p: String) 1877 } 1878 """ 1879 ), 1880 signature( 1881 """ 1882 // Signature format: 2.0 1883 package test.pkg { 1884 public interface Foo { 1885 method public void foo(String...); 1886 } 1887 } 1888 """ 1889 ), 1890 ) { 1891 val varargsType = 1892 codebase.assertClass("test.pkg.Foo").methods().single().parameters().single().type() 1893 assertThat(varargsType.toSimpleType()).isEqualTo("java.lang.String...") 1894 } 1895 } 1896 1897 @Test 1898 fun `Test toSimpleType on varargs generic parameter`() { 1899 runCodebaseTest( 1900 java( 1901 @Suppress("unchecked") 1902 """ 1903 package test.pkg; 1904 public interface Foo { 1905 void foo(Comparable<? super String>...p); 1906 } 1907 """ 1908 ), 1909 kotlin( 1910 """ 1911 package test.pkg 1912 interface Foo { 1913 fun foo(vararg p: Comparable<String>) 1914 } 1915 """ 1916 ), 1917 signature( 1918 """ 1919 // Signature format: 2.0 1920 package test.pkg { 1921 public interface Foo { 1922 method public void foo(Comparable<? super String>...); 1923 } 1924 } 1925 """ 1926 ), 1927 ) { 1928 val varargsType = 1929 codebase.assertClass("test.pkg.Foo").methods().single().parameters().single().type() 1930 assertThat(varargsType.toSimpleType()) 1931 .isEqualTo("Comparable<? super java.lang.String>...") 1932 } 1933 } 1934 1935 @Test 1936 fun `Test toSimpleType on nested class`() { 1937 runCodebaseTest( 1938 java( 1939 """ 1940 package test.pkg; 1941 public interface Foo { 1942 void foo(Thread.UncaughtExceptionHandler p); 1943 } 1944 """ 1945 ), 1946 kotlin( 1947 """ 1948 package test.pkg 1949 interface Foo { 1950 fun foo(p: Thread.UncaughtExceptionHandler) 1951 } 1952 """ 1953 ), 1954 signature( 1955 """ 1956 // Signature format: 2.0 1957 package test.pkg { 1958 public interface Foo { 1959 method public void foo(Thread.UncaughtExceptionHandler); 1960 } 1961 } 1962 """ 1963 ), 1964 ) { 1965 val varargsType = 1966 codebase.assertClass("test.pkg.Foo").methods().single().parameters().single().type() 1967 assertThat(varargsType.toSimpleType()) 1968 .isEqualTo("java.lang.Thread.UncaughtExceptionHandler") 1969 } 1970 } 1971 1972 @Test 1973 fun `Non-last varargs param in deprecated method`() { 1974 runCodebaseTest( 1975 kotlin( 1976 """ 1977 package test.pkg 1978 class Foo { 1979 fun notDeprecated(vararg str: String, i: Int) = Unit 1980 @Deprecated(message = "message", level = DeprecationLevel.WARNING) 1981 fun deprecatedWarning(vararg str: String, i: Int) = Unit 1982 @Deprecated(message = "message", level = DeprecationLevel.ERROR) 1983 fun deprecatedError(vararg str: String, i: Int) = Unit 1984 @Deprecated(message = "message", level = DeprecationLevel.HIDDEN) 1985 fun deprecatedHidden(vararg str: String, i: Int) = Unit 1986 } 1987 """ 1988 ) 1989 ) { 1990 val foo = codebase.assertClass("test.pkg.Foo") 1991 val notDeprecated = foo.methods().single { it.name() == "notDeprecated" } 1992 val deprecatedWarning = foo.methods().single { it.name() == "deprecatedWarning" } 1993 val deprecatedError = foo.methods().single { it.name() == "deprecatedError" } 1994 val deprecatedHidden = foo.methods().single { it.name() == "deprecatedHidden" } 1995 1996 fun MethodItem.firstParameterIsVarargs() = 1997 (parameters().first().type() as ArrayTypeItem).isVarargs 1998 1999 assertThat(notDeprecated.firstParameterIsVarargs()).isFalse() 2000 assertThat(deprecatedWarning.firstParameterIsVarargs()).isFalse() 2001 assertThat(deprecatedError.firstParameterIsVarargs()).isFalse() 2002 assertThat(deprecatedHidden.firstParameterIsVarargs()).isFalse() 2003 } 2004 } 2005 } 2006