1 /* 2 * 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.ClassItem 21 import com.android.tools.metalava.model.ClassTypeItem 22 import com.android.tools.metalava.model.PrimitiveTypeItem 23 import com.android.tools.metalava.model.ReferenceTypeItem 24 import com.android.tools.metalava.model.TypeArgumentTypeItem 25 import com.android.tools.metalava.model.VariableTypeItem 26 import com.android.tools.metalava.model.WildcardTypeItem 27 import com.android.tools.metalava.model.testsuite.BaseModelTest 28 import com.android.tools.metalava.testing.java 29 import com.android.tools.metalava.testing.kotlin 30 import com.google.common.truth.Truth.assertThat 31 import com.google.common.truth.Truth.assertWithMessage 32 import org.junit.Test 33 34 class CommonTypeItemTest : BaseModelTest() { 35 @Test Test primitive typesnull36 fun `Test primitive types`() { 37 runCodebaseTest( 38 java( 39 """ 40 package test.pkg; 41 public class Foo { 42 public void foo( 43 boolean p0, 44 byte p1, 45 char p2, 46 double p3, 47 float p4, 48 int p5, 49 long p6, 50 short p7 51 ) {} 52 } 53 """ 54 ), 55 kotlin( 56 """ 57 package test.pkg 58 class Foo { 59 fun foo( 60 p0: Boolean, 61 p1: Byte, 62 p2: Char, 63 p3: Double, 64 p4: Float, 65 p5: Int, 66 p6: Long, 67 p7: Short 68 ) = Unit 69 } 70 """ 71 ), 72 signature( 73 """ 74 // Signature format: 3.0 75 package test.pkg { 76 public class Foo { 77 ctor public Foo(); 78 method public void foo(boolean, byte, char, double, float, int, long, short); 79 } 80 } 81 """ 82 .trimIndent() 83 ) 84 ) { 85 val method = codebase.assertClass("test.pkg.Foo").methods().single() 86 87 val returnType = method.returnType() 88 assertThat(returnType).isInstanceOf(PrimitiveTypeItem::class.java) 89 assertThat((returnType as PrimitiveTypeItem).kind) 90 .isEqualTo(PrimitiveTypeItem.Primitive.VOID) 91 92 val expectedParamTypes = 93 listOf( 94 PrimitiveTypeItem.Primitive.BOOLEAN, 95 PrimitiveTypeItem.Primitive.BYTE, 96 PrimitiveTypeItem.Primitive.CHAR, 97 PrimitiveTypeItem.Primitive.DOUBLE, 98 PrimitiveTypeItem.Primitive.FLOAT, 99 PrimitiveTypeItem.Primitive.INT, 100 PrimitiveTypeItem.Primitive.LONG, 101 PrimitiveTypeItem.Primitive.SHORT 102 ) 103 104 val params = method.parameters().map { it.type() } 105 assertThat(params).hasSize(expectedParamTypes.size) 106 for ((param, expectedKind) in params.zip(expectedParamTypes)) { 107 assertThat(param).isInstanceOf(PrimitiveTypeItem::class.java) 108 assertThat((param as PrimitiveTypeItem).kind).isEqualTo(expectedKind) 109 } 110 } 111 } 112 113 @Test Test primitive array typesnull114 fun `Test primitive array types`() { 115 runCodebaseTest( 116 java( 117 """ 118 package test.pkg; 119 public class Foo { 120 public void foo( 121 int[] p0, 122 char[] p1 123 ) {} 124 } 125 """ 126 ), 127 // The Kotlin equivalent can be interpreted with java.lang types instead of primitives 128 signature( 129 """ 130 // Signature format: 3.0 131 package test.pkg { 132 public class Foo { 133 ctor public Foo(); 134 method public void foo(int[], char[]); 135 } 136 } 137 """ 138 .trimIndent() 139 ) 140 ) { 141 val method = codebase.assertClass("test.pkg.Foo").methods().single() 142 143 val paramTypes = method.parameters().map { it.type() } 144 assertThat(paramTypes).hasSize(2) 145 146 // int[] 147 val intArray = paramTypes[0] 148 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 149 val int = (intArray as ArrayTypeItem).componentType 150 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 151 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 152 assertThat(intArray.isVarargs).isFalse() 153 154 // char[] 155 val charArray = paramTypes[1] 156 assertThat(charArray).isInstanceOf(ArrayTypeItem::class.java) 157 val char = (charArray as ArrayTypeItem).componentType 158 assertThat(char).isInstanceOf(PrimitiveTypeItem::class.java) 159 assertThat((char as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.CHAR) 160 assertThat(charArray.isVarargs).isFalse() 161 } 162 } 163 164 @Test Test primitive vararg typesnull165 fun `Test primitive vararg types`() { 166 runCodebaseTest( 167 java( 168 """ 169 package test.pkg; 170 public class Foo { 171 public void foo(int... p0) {} 172 } 173 """ 174 ), 175 kotlin( 176 """ 177 package test.pkg 178 class Foo { 179 fun foo(vararg p0: Int 180 ) = Unit 181 } 182 """ 183 ), 184 signature( 185 """ 186 // Signature format: 3.0 187 package test.pkg { 188 public class Foo { 189 ctor public Foo(); 190 method public void foo(int...); 191 } 192 } 193 """ 194 .trimIndent() 195 ) 196 ) { 197 val method = codebase.assertClass("test.pkg.Foo").methods().single() 198 199 val paramTypes = method.parameters().map { it.type() } 200 assertThat(paramTypes).hasSize(1) 201 202 // int... / vararg int 203 val intArray = paramTypes[0] 204 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 205 val int = (intArray as ArrayTypeItem).componentType 206 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 207 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 208 assertThat(intArray.isVarargs).isTrue() 209 } 210 } 211 212 @Test Test multidimensional primitive array typesnull213 fun `Test multidimensional primitive array types`() { 214 runCodebaseTest( 215 java( 216 """ 217 package test.pkg; 218 public class Foo { 219 public void foo( 220 int[][] p0, 221 char[]... p1 222 ) {} 223 } 224 """ 225 ), 226 // The Kotlin equivalent can be interpreted with java.lang types instead of primitives 227 signature( 228 """ 229 // Signature format: 3.0 230 package test.pkg { 231 public class Foo { 232 ctor public Foo(); 233 method public void foo(int[][], char[]...); 234 } 235 } 236 """ 237 .trimIndent() 238 ) 239 ) { 240 val method = codebase.assertClass("test.pkg.Foo").methods().single() 241 242 val paramTypes = method.parameters().map { it.type() } 243 assertThat(paramTypes).hasSize(2) 244 245 // int[][] 246 val intArrayArray = paramTypes[0] 247 assertThat(intArrayArray).isInstanceOf(ArrayTypeItem::class.java) 248 assertThat((intArrayArray as ArrayTypeItem).isVarargs).isFalse() 249 250 val intArray = intArrayArray.componentType 251 assertThat(intArray).isInstanceOf(ArrayTypeItem::class.java) 252 assertThat((intArray as ArrayTypeItem).isVarargs).isFalse() 253 254 val int = intArray.componentType 255 assertThat(int).isInstanceOf(PrimitiveTypeItem::class.java) 256 assertThat((int as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.INT) 257 258 // char[]... 259 val charArrayArray = paramTypes[1] 260 assertThat(charArrayArray).isInstanceOf(ArrayTypeItem::class.java) 261 assertThat((charArrayArray as ArrayTypeItem).isVarargs).isTrue() 262 263 val charArray = charArrayArray.componentType 264 assertThat(charArray).isInstanceOf(ArrayTypeItem::class.java) 265 assertThat((charArray as ArrayTypeItem).isVarargs).isFalse() 266 267 val char = charArray.componentType 268 assertThat(char).isInstanceOf(PrimitiveTypeItem::class.java) 269 assertThat((char as PrimitiveTypeItem).kind).isEqualTo(PrimitiveTypeItem.Primitive.CHAR) 270 } 271 } 272 273 @Test Test class array typesnull274 fun `Test class array types`() { 275 runCodebaseTest( 276 java( 277 """ 278 package test.pkg; 279 public class Foo { 280 public void foo( 281 java.lang.String[] p0, 282 java.lang.String[][] p1, 283 java.lang.String... p2 284 ) {} 285 } 286 """ 287 ), 288 kotlin( 289 """ 290 package test.pkg 291 class Foo { 292 fun foo( 293 p0: Array<String>, 294 p1: Array<Array<String>>, 295 vararg p2: String 296 ) = Unit 297 } 298 """ 299 ), 300 signature( 301 """ 302 // Signature format: 3.0 303 package test.pkg { 304 public class Foo { 305 ctor public Foo(); 306 method public void foo(String![]!, String![]![]!, java.lang.String!...); 307 } 308 } 309 """ 310 .trimIndent() 311 ) 312 ) { 313 val method = codebase.assertClass("test.pkg.Foo").methods().single() 314 315 val paramTypes = method.parameters().map { it.type() } 316 assertThat(paramTypes).hasSize(3) 317 318 // String[] / Array<String> 319 val simpleArray = paramTypes[0] 320 assertThat(simpleArray).isInstanceOf(ArrayTypeItem::class.java) 321 assertThat((simpleArray as ArrayTypeItem).componentType.isString()).isTrue() 322 assertThat(simpleArray.isVarargs).isFalse() 323 324 // String[][] / Array<Array<String>> 325 val twoDimensionalArray = paramTypes[1] 326 assertThat(twoDimensionalArray).isInstanceOf(ArrayTypeItem::class.java) 327 assertThat((twoDimensionalArray as ArrayTypeItem).isVarargs).isFalse() 328 val innerArray = twoDimensionalArray.componentType 329 assertThat(innerArray).isInstanceOf(ArrayTypeItem::class.java) 330 assertThat((innerArray as ArrayTypeItem).componentType.isString()).isTrue() 331 assertThat(innerArray.isVarargs).isFalse() 332 333 // String... / vararg String 334 val varargs = paramTypes[2] 335 assertThat(twoDimensionalArray).isInstanceOf(ArrayTypeItem::class.java) 336 assertThat((varargs as ArrayTypeItem).componentType.isString()).isTrue() 337 assertThat(varargs.isVarargs).isTrue() 338 } 339 } 340 341 @Test Test wildcard typesnull342 fun `Test wildcard types`() { 343 runCodebaseTest( 344 java( 345 """ 346 package test.pkg; 347 public class Foo<T> { 348 public void foo( 349 Foo<?> p0, 350 Foo<? extends java.lang.String> p1, 351 Foo<? super java.lang.String> p2, 352 Foo<? extends java.lang.String[]> p3 353 ) {} 354 } 355 """ 356 ), 357 kotlin( 358 """ 359 package test.pkg 360 class Foo<T> { 361 fun foo( 362 p0: Foo<*>, 363 p1: Foo<out String>, 364 p2: Foo<in String>, 365 p3: Foo<out Array<String>> 366 ) = Unit 367 } 368 """ 369 ), 370 signature( 371 """ 372 // Signature format: 3.0 373 package test.pkg { 374 public class Foo<T> { 375 ctor public Foo(); 376 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[]>!); 377 } 378 } 379 """ 380 .trimIndent() 381 ) 382 ) { 383 val method = codebase.assertClass("test.pkg.Foo").methods().single() 384 385 val wildcardTypes = 386 method.parameters().map { 387 val paramType = it.type() 388 assertThat(paramType).isInstanceOf(ClassTypeItem::class.java) 389 assertThat((paramType as ClassTypeItem).arguments).hasSize(1) 390 paramType.arguments.single() 391 } 392 assertThat(wildcardTypes).hasSize(4) 393 394 // Foo<?> / Foo<*> 395 // Unbounded wildcards implicitly have an Object extends bound 396 val unboundedWildcard = wildcardTypes[0] 397 assertThat(unboundedWildcard).isInstanceOf(WildcardTypeItem::class.java) 398 val unboundedExtendsBound = (unboundedWildcard as WildcardTypeItem).extendsBound 399 assertThat(unboundedExtendsBound).isNotNull() 400 assertThat(unboundedExtendsBound!!.isJavaLangObject()).isTrue() 401 assertThat(unboundedWildcard.superBound).isNull() 402 403 // Foo<? extends String> / Foo<out String> 404 val extendsBoundWildcard = wildcardTypes[1] 405 assertThat(extendsBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 406 val extendsBound = (extendsBoundWildcard as WildcardTypeItem).extendsBound 407 assertThat(extendsBound).isNotNull() 408 assertThat(extendsBound!!.isString()).isTrue() 409 assertThat(extendsBoundWildcard.superBound).isNull() 410 411 // Foo<? super String> / Foo<in String> 412 // A super bounded wildcard implicitly has an Object extends bound 413 val superBoundWildcard = wildcardTypes[2] 414 assertThat(superBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 415 val superExtendsBound = (superBoundWildcard as WildcardTypeItem).extendsBound 416 assertThat(superExtendsBound).isNotNull() 417 assertThat(superExtendsBound!!.isJavaLangObject()).isTrue() 418 val superBound = superBoundWildcard.superBound 419 assertThat(superBound).isNotNull() 420 assertThat(superBound!!.isString()).isTrue() 421 422 // Foo<? extends java.lang.String[]> / Foo<in Array<String>> 423 val arrayExtendsBoundWildcard = wildcardTypes[3] 424 assertThat(arrayExtendsBoundWildcard).isInstanceOf(WildcardTypeItem::class.java) 425 val arrayExtendsBound = (arrayExtendsBoundWildcard as WildcardTypeItem).extendsBound 426 assertThat(arrayExtendsBound).isNotNull() 427 assertThat(arrayExtendsBound).isInstanceOf(ArrayTypeItem::class.java) 428 assertThat((arrayExtendsBound as ArrayTypeItem).componentType.isString()).isTrue() 429 } 430 } 431 432 @Test Test variable typesnull433 fun `Test variable types`() { 434 runCodebaseTest( 435 java( 436 """ 437 package test.pkg; 438 public class Foo<C> { 439 public <M> void foo(C p0, M p1) {} 440 } 441 """ 442 ), 443 kotlin( 444 """ 445 package test.pkg 446 class Foo<C> { 447 fun <M> foo(p0: C, p1: M) = Unit 448 } 449 """ 450 ), 451 signature( 452 """ 453 // Signature format: 3.0 454 package test.pkg { 455 public class Foo<C> { 456 ctor public Foo(); 457 method public <M> void foo(C!, M!); 458 } 459 } 460 """ 461 .trimIndent() 462 ) 463 ) { 464 val clz = codebase.assertClass("test.pkg.Foo") 465 val classTypeParam = clz.typeParameterList.single() 466 val method = clz.methods().single() 467 val methodTypeParam = method.typeParameterList.single() 468 val paramTypes = method.parameters().map { it.type() } 469 assertThat(paramTypes).hasSize(2) 470 471 val classTypeVariable = paramTypes[0] 472 classTypeVariable.assertReferencesTypeParameter(classTypeParam) 473 assertThat((classTypeVariable as VariableTypeItem).name).isEqualTo("C") 474 475 val methodTypeVariable = paramTypes[1] 476 methodTypeVariable.assertReferencesTypeParameter(methodTypeParam) 477 assertThat((methodTypeVariable as VariableTypeItem).name).isEqualTo("M") 478 } 479 } 480 481 @Test Test method return type variable typesnull482 fun `Test method return type variable types`() { 483 runCodebaseTest( 484 java( 485 """ 486 package test.pkg; 487 public class Foo<T> { 488 public T bar1() {} 489 public <A extends java.lang.String> A bar2() {} 490 public <A extends java.lang.String> T bar3() {} 491 public <T extends java.lang.String> T bar4() {} 492 } 493 """ 494 ), 495 kotlin( 496 """ 497 package test.pkg 498 class Foo<T> { 499 fun bar1(): T {} 500 fun <A: java.lang.String> bar2(): A {} 501 fun <A: java.lang.String> bar3(): T {} 502 fun <T: java.lang.String> bar4(): T {} 503 } 504 """ 505 ), 506 signature( 507 """ 508 // Signature format: 3.0 509 package test.pkg { 510 public class Foo<T> { 511 method public T bar1(); 512 method public <A extends java.lang.String> A bar2(); 513 method public <A extends java.lang.String> T bar3(); 514 method public <T extends java.lang.String> T bar4(); 515 } 516 } 517 """ 518 .trimIndent() 519 ) 520 ) { 521 val foo = codebase.assertClass("test.pkg.Foo") 522 val fooTypeParam = foo.typeParameterList.single() 523 524 val bar1 = foo.methods().single { it.name() == "bar1" } 525 val bar1Return = bar1.returnType() 526 bar1Return.assertReferencesTypeParameter(fooTypeParam) 527 528 val bar2 = foo.methods().single { it.name() == "bar2" } 529 val bar2TypeParam = bar2.typeParameterList.single() 530 val bar2Return = bar2.returnType() 531 bar2Return.assertReferencesTypeParameter(bar2TypeParam) 532 533 val bar3 = foo.methods().single { it.name() == "bar3" } 534 val bar3Return = bar3.returnType() 535 bar3Return.assertReferencesTypeParameter(fooTypeParam) 536 537 val bar4 = foo.methods().single { it.name() == "bar4" } 538 val bar4TypeParam = bar4.typeParameterList.single() 539 val bar4Return = bar4.returnType() 540 bar4Return.assertReferencesTypeParameter(bar4TypeParam) 541 } 542 } 543 544 @Test Test method parameter type variable typesnull545 fun `Test method parameter type variable types`() { 546 runCodebaseTest( 547 java( 548 """ 549 package test.pkg; 550 public class Foo<T> { 551 public void bar1(T p0) {} 552 public <A extends java.lang.String> void bar2(A p0) {} 553 public <A extends java.lang.String> void bar3(T p0) {} 554 public <T extends java.lang.String> void bar4(T p0) {} 555 } 556 """ 557 ), 558 kotlin( 559 """ 560 package test.pkg 561 class Foo<T> { 562 fun bar1(p0: T) = Unit 563 fun <A: java.lang.String> bar2(p0: A) = Unit 564 fun <A: java.lang.String> bar3(p0: T) = Unit 565 fun <T: java.lang.String> bar4(p0: T) = Unit 566 } 567 """ 568 ), 569 signature( 570 """ 571 // Signature format: 3.0 572 package test.pkg { 573 public class Foo<T> { 574 method public void bar1(T p); 575 method public <A extends java.lang.String> void bar2(A p); 576 method public <A extends java.lang.String> void bar3(T p); 577 method public <T extends java.lang.String> void bar4(T p); 578 } 579 } 580 """ 581 .trimIndent() 582 ) 583 ) { 584 val foo = codebase.assertClass("test.pkg.Foo") 585 val fooParam = foo.typeParameterList.single() 586 587 val bar1 = foo.methods().single { it.name() == "bar1" } 588 val bar1Param = bar1.parameters().single().type() 589 bar1Param.assertReferencesTypeParameter(fooParam) 590 591 val bar2 = foo.methods().single { it.name() == "bar2" } 592 val bar2TypeParam = bar2.typeParameterList.single() 593 val bar2Param = bar2.parameters().single().type() 594 bar2Param.assertReferencesTypeParameter(bar2TypeParam) 595 596 val bar3 = foo.methods().single { it.name() == "bar3" } 597 val bar3Param = bar3.parameters().single().type() 598 bar3Param.assertReferencesTypeParameter(fooParam) 599 600 val bar4 = foo.methods().single { it.name() == "bar4" } 601 val bar4TypeParam = bar4.typeParameterList.single() 602 val bar4Param = bar4.parameters().single().type() 603 bar4Param.assertReferencesTypeParameter(bar4TypeParam) 604 } 605 } 606 607 @Test Test field type variable typesnull608 fun `Test field type variable types`() { 609 runCodebaseTest( 610 java( 611 """ 612 package test.pkg; 613 public class Foo<T> { 614 public T foo; 615 } 616 """ 617 .trimIndent() 618 ), 619 kotlin( 620 """ 621 package test.pkg 622 class Foo<T> { 623 @JvmField val foo: T 624 } 625 """ 626 ), 627 signature( 628 """ 629 // Signature format: 3.0 630 package test.pkg { 631 public class Foo<T> { 632 field public T foo; 633 } 634 } 635 """ 636 .trimIndent() 637 ) 638 ) { 639 val foo = codebase.assertClass("test.pkg.Foo") 640 val fooParam = foo.typeParameterList.single() 641 642 val fieldType = foo.fields().single { it.name() == "foo" }.type() 643 fieldType.assertReferencesTypeParameter(fooParam) 644 } 645 } 646 647 @Test Test property type variable typesnull648 fun `Test property type variable types`() { 649 runCodebaseTest( 650 // No java equivalent 651 kotlin( 652 """ 653 package test.pkg 654 class Foo<T> { 655 val foo: T 656 } 657 """ 658 .trimIndent() 659 ), 660 signature( 661 """ 662 // Signature format: 3.0 663 package test.pkg { 664 public class Foo<T> { 665 property public T foo; 666 } 667 } 668 """ 669 .trimIndent() 670 ) 671 ) { 672 val foo = codebase.assertClass("test.pkg.Foo") 673 val fooParam = foo.typeParameterList.single() 674 675 val propertyType = foo.properties().single { it.name() == "foo" }.type() 676 propertyType.assertReferencesTypeParameter(fooParam) 677 } 678 } 679 680 @Test Test class typesnull681 fun `Test class types`() { 682 runCodebaseTest( 683 java( 684 """ 685 package test.pkg; 686 public class Foo { 687 public <T> void foo( 688 java.lang.String p0, 689 java.util.List<java.lang.String> p1, 690 java.util.List<java.lang.String[]> p2, 691 java.util.Map<java.lang.String, Foo> p3 692 ) {} 693 } 694 """ 695 ), 696 kotlin( 697 """ 698 package test.pkg 699 class Foo { 700 fun <T> foo( 701 p0: String, 702 p1: List<String>, 703 p2: List<Array<String>>, 704 p3: Map<String, Foo> 705 ) = Unit 706 } 707 """ 708 ), 709 signature( 710 """ 711 // Signature format: 3.0 712 package test.pkg { 713 public class Foo { 714 ctor public Foo(); 715 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!>!); 716 } 717 } 718 """ 719 .trimIndent() 720 ) 721 ) { 722 val method = codebase.assertClass("test.pkg.Foo").methods().single() 723 val paramTypes = method.parameters().map { it.type() } 724 725 val stringType = paramTypes[0] 726 assertThat(stringType).isInstanceOf(ClassTypeItem::class.java) 727 assertThat((stringType as ClassTypeItem).qualifiedName).isEqualTo("java.lang.String") 728 assertThat(stringType.className).isEqualTo("String") 729 assertThat(stringType.arguments).isEmpty() 730 731 // List<String> 732 val stringListType = paramTypes[1] 733 assertThat(stringListType).isInstanceOf(ClassTypeItem::class.java) 734 assertThat((stringListType as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 735 assertThat(stringListType.className).isEqualTo("List") 736 assertThat(stringListType.arguments).hasSize(1) 737 assertThat(stringListType.arguments.single().isString()).isTrue() 738 739 // List<String[]> / List<Array<String>> 740 val arrayListType = paramTypes[2] 741 assertThat(arrayListType).isInstanceOf(ClassTypeItem::class.java) 742 assertThat((arrayListType as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 743 assertThat(arrayListType.arguments).hasSize(1) 744 val arrayType = arrayListType.arguments.single() 745 assertThat(arrayType).isInstanceOf(ArrayTypeItem::class.java) 746 assertThat((arrayType as ArrayTypeItem).componentType.isString()).isTrue() 747 748 // Map<String, Foo> 749 val mapType = paramTypes[3] 750 assertThat(mapType).isInstanceOf(ClassTypeItem::class.java) 751 assertThat((mapType as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map") 752 assertThat(mapType.arguments).hasSize(2) 753 val mapKeyType = mapType.arguments.first() 754 assertThat(mapKeyType).isInstanceOf(ClassTypeItem::class.java) 755 assertThat((mapKeyType as ClassTypeItem).isString()).isTrue() 756 val mapValueType = mapType.arguments.last() 757 assertThat(mapValueType).isInstanceOf(ClassTypeItem::class.java) 758 assertThat((mapValueType as ClassTypeItem).qualifiedName).isEqualTo("test.pkg.Foo") 759 } 760 } 761 762 @Test Test inner typesnull763 fun `Test inner types`() { 764 runCodebaseTest( 765 java( 766 """ 767 package test.pkg; 768 public class Outer { 769 public class Middle { 770 public class Inner {} 771 } 772 773 public Outer.Middle.Inner foo() { 774 return new Outer.Middle.Inner(); 775 } 776 } 777 """ 778 ), 779 kotlin( 780 """ 781 package test.pkg 782 class Outer { 783 inner class Middle { 784 inner class Inner 785 } 786 787 fun foo(): Outer.Middle.Inner { 788 return Outer.Middle.Inner() 789 } 790 } 791 """ 792 ), 793 signature( 794 """ 795 // Signature format: 3.0 796 package test.pkg { 797 public class Outer { 798 ctor public Outer(); 799 method public test.pkg.Outer.Middle.Inner foo(); 800 } 801 public class Outer.Middle { 802 ctor public Outer.Middle(); 803 } 804 public class Outer.Middle.Inner { 805 ctor public Outer.Middle.Inner(); 806 } 807 } 808 """ 809 .trimIndent() 810 ) 811 ) { 812 val method = codebase.assertClass("test.pkg.Outer").methods().single() 813 814 // Outer.Middle.Inner 815 val innerType = method.returnType() 816 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 817 assertThat((innerType as ClassTypeItem).qualifiedName) 818 .isEqualTo("test.pkg.Outer.Middle.Inner") 819 assertThat(innerType.className).isEqualTo("Inner") 820 assertThat(innerType.arguments).isEmpty() 821 822 val middleType = innerType.outerClassType 823 assertThat(middleType).isNotNull() 824 assertThat(middleType!!.qualifiedName).isEqualTo("test.pkg.Outer.Middle") 825 assertThat(middleType.className).isEqualTo("Middle") 826 assertThat(middleType.arguments).isEmpty() 827 828 val outerType = middleType.outerClassType 829 assertThat(outerType).isNotNull() 830 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg.Outer") 831 assertThat(outerType.className).isEqualTo("Outer") 832 assertThat(outerType.arguments).isEmpty() 833 assertThat(outerType.outerClassType).isNull() 834 } 835 } 836 837 @Test Test inner types from classpathnull838 fun `Test inner types from classpath`() { 839 runCodebaseTest( 840 java( 841 """ 842 package test.pkg; 843 844 import java.util.Map; 845 846 public class Test { 847 public Map.Entry<String,String> foo() { 848 return new Map.Entry<String,String>(); 849 } 850 } 851 """ 852 ), 853 kotlin( 854 """ 855 package test.pkg 856 857 import java.util.Map 858 859 class Test { 860 fun foo(): Map.Entry<String,String> { 861 return Map.Entry<String,String>() 862 } 863 } 864 """ 865 ), 866 signature( 867 """ 868 // Signature format: 3.0 869 package test.pkg { 870 public class Test { 871 ctor public Outer(); 872 method public java.util.Map.Entry<java.lang.String,java.lang.String> foo(); 873 } 874 } 875 """ 876 .trimIndent() 877 ) 878 ) { 879 val method = codebase.assertClass("test.pkg.Test").methods().single() 880 881 // Map.Entry<String,String> 882 val innerType = method.returnType() 883 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 884 assertThat((innerType as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map.Entry") 885 assertThat(innerType.className).isEqualTo("Entry") 886 887 val outerType = innerType.outerClassType 888 assertThat(outerType).isNotNull() 889 assertThat(outerType!!.qualifiedName).isEqualTo("java.util.Map") 890 assertThat(outerType.className).isEqualTo("Map") 891 assertThat(outerType.arguments).hasSize(0) 892 assertThat(outerType.outerClassType).isNull() 893 } 894 } 895 896 @Test Test inner parameterized typesnull897 fun `Test inner parameterized types`() { 898 runCodebaseTest( 899 java( 900 """ 901 package test.pkg; 902 public class Outer<O> { 903 public class Inner<I> { 904 } 905 906 public <P1, P2> Outer<P1>.Inner<P2> foo() { 907 return new Outer<P1>.Inner<P2>(); 908 } 909 } 910 """ 911 ), 912 kotlin( 913 """ 914 package test.pkg 915 class Outer<O> { 916 inner class Inner<I> 917 918 fun <P1, P2> foo(): Outer<P1>.Inner<P2> { 919 return Outer<P1>.Inner<P2>() 920 } 921 } 922 """ 923 ), 924 signature( 925 """ 926 // Signature format: 3.0 927 package test.pkg { 928 public class Outer<O> { 929 ctor public Outer(); 930 method public <P1, P2> test.pkg.Outer<P1!>.Inner<P2!>! foo(); 931 } 932 public class Outer.Inner<I> { 933 ctor public Outer.Inner(); 934 } 935 } 936 """ 937 .trimIndent() 938 ) 939 ) { 940 val method = codebase.assertClass("test.pkg.Outer").methods().single() 941 val methodTypeParameters = method.typeParameterList 942 assertThat(methodTypeParameters).hasSize(2) 943 val p1 = methodTypeParameters[0] 944 val p2 = methodTypeParameters[1] 945 946 // Outer<P1>.Inner<P2> 947 val innerType = method.returnType() 948 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 949 assertThat((innerType as ClassTypeItem).qualifiedName).isEqualTo("test.pkg.Outer.Inner") 950 assertThat(innerType.className).isEqualTo("Inner") 951 assertThat(innerType.arguments).hasSize(1) 952 val innerTypeArgument = innerType.arguments.single() 953 innerTypeArgument.assertReferencesTypeParameter(p2) 954 assertThat((innerTypeArgument as VariableTypeItem).name).isEqualTo("P2") 955 956 val outerType = innerType.outerClassType 957 assertThat(outerType).isNotNull() 958 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg.Outer") 959 assertThat(outerType.className).isEqualTo("Outer") 960 assertThat(outerType.outerClassType).isNull() 961 assertThat(outerType.arguments).hasSize(1) 962 val outerClassTypeArgument = outerType.arguments.single() 963 outerClassTypeArgument.assertReferencesTypeParameter(p1) 964 assertThat((outerClassTypeArgument as VariableTypeItem).name).isEqualTo("P1") 965 } 966 } 967 968 @Test Test inner parameterized types without explicit outer typenull969 fun `Test inner parameterized types without explicit outer type`() { 970 runCodebaseTest( 971 inputSet( 972 java( 973 """ 974 package test.pkg; 975 976 import test.pkg1.Outer.Middle.Inner; 977 978 public class Test { 979 public Inner<String> foo() { 980 return new Inner<String>(); 981 } 982 } 983 """ 984 ), 985 java( 986 """ 987 package test.pkg1; 988 989 public class Outer<O> { 990 public class Middle { 991 public class Inner<I> {} 992 } 993 } 994 """ 995 ), 996 ), 997 inputSet( 998 signature( 999 """ 1000 // Signature format: 3.0 1001 package test.pkg1 { 1002 public class Outer<O> { 1003 ctor public Outer(); 1004 } 1005 public class Outer.Middle { 1006 ctor public Outer.Middle(); 1007 } 1008 public class Outer.Middle.Inner<I> { 1009 ctor public Outer.Middle.Inner(); 1010 } 1011 } 1012 """ 1013 ), 1014 signature( 1015 """ 1016 // Signature format: 3.0 1017 package test.pkg { 1018 public class Test { 1019 ctor public Test(); 1020 method public test.pkg1.Outer.Middle.Inner<String> foo(); 1021 } 1022 } 1023 """ 1024 ) 1025 ) 1026 ) { 1027 val method = codebase.assertClass("test.pkg.Test").methods().single() 1028 1029 val innerType = method.returnType() 1030 assertThat(innerType).isInstanceOf(ClassTypeItem::class.java) 1031 assertThat((innerType as ClassTypeItem).qualifiedName) 1032 .isEqualTo("test.pkg1.Outer.Middle.Inner") 1033 assertThat(innerType.className).isEqualTo("Inner") 1034 assertThat(innerType.arguments).hasSize(1) 1035 1036 val middleType = innerType.outerClassType 1037 assertThat(middleType).isNotNull() 1038 assertThat(middleType!!.qualifiedName).isEqualTo("test.pkg1.Outer.Middle") 1039 assertThat(middleType.className).isEqualTo("Middle") 1040 assertThat(middleType.arguments).hasSize(0) 1041 1042 val outerType = middleType.outerClassType 1043 assertThat(outerType).isNotNull() 1044 assertThat(outerType!!.qualifiedName).isEqualTo("test.pkg1.Outer") 1045 assertThat(outerType.className).isEqualTo("Outer") 1046 assertThat(outerType.outerClassType).isNull() 1047 assertThat(outerType.arguments).hasSize(0) 1048 } 1049 } 1050 1051 @Test Test superclass and interface types using type variablesnull1052 fun `Test superclass and interface types using type variables`() { 1053 runCodebaseTest( 1054 java( 1055 """ 1056 package test.pkg; 1057 1058 public class Cache<Query, Result> extends java.util.HashMap<Query,Result> {} 1059 1060 public class MyList<E> implements java.util.List<E> {} 1061 """ 1062 .trimIndent() 1063 ), 1064 kotlin( 1065 """ 1066 package test.pkg 1067 1068 class Cache<Query, Result> : java.util.HashMap<Query, Result> 1069 1070 class MyList<E> : java.util.List<E> 1071 """ 1072 .trimIndent() 1073 ), 1074 signature( 1075 """ 1076 // Signature format: 2.0 1077 package test.pkg { 1078 public class Cache<Query, Result> extends java.util.HashMap<Query,Result> { 1079 } 1080 public class MyList<E> implements java.util.List<E> { 1081 } 1082 } 1083 """ 1084 .trimIndent() 1085 ) 1086 ) { 1087 // Verify that the Cache superclass type uses the Cache type variables 1088 val cache = codebase.assertClass("test.pkg.Cache") 1089 val cacheTypeParams = cache.typeParameterList 1090 assertThat(cacheTypeParams).hasSize(2) 1091 val queryParam = cacheTypeParams[0] 1092 val resultParam = cacheTypeParams[1] 1093 1094 val cacheSuperclassType = cache.superClassType() 1095 assertThat(cacheSuperclassType).isInstanceOf(ClassTypeItem::class.java) 1096 assertThat((cacheSuperclassType as ClassTypeItem).qualifiedName) 1097 .isEqualTo("java.util.HashMap") 1098 assertThat(cacheSuperclassType.arguments).hasSize(2) 1099 1100 val queryVar = cacheSuperclassType.arguments[0] 1101 queryVar.assertReferencesTypeParameter(queryParam) 1102 1103 val resultVar = cacheSuperclassType.arguments[1] 1104 resultVar.assertReferencesTypeParameter(resultParam) 1105 1106 // Verify that the MyList interface type uses the MyList type variable 1107 val myList = codebase.assertClass("test.pkg.MyList") 1108 val myListTypeParams = myList.typeParameterList 1109 assertThat(myListTypeParams).hasSize(1) 1110 val eParam = myListTypeParams.single() 1111 1112 val myListInterfaces = myList.interfaceTypes() 1113 assertThat(myListInterfaces).hasSize(1) 1114 1115 val myListInterfaceType = myListInterfaces.single() 1116 assertThat(myListInterfaceType).isInstanceOf(ClassTypeItem::class.java) 1117 assertThat(myListInterfaceType.qualifiedName).isEqualTo("java.util.List") 1118 assertThat(myListInterfaceType.arguments).hasSize(1) 1119 1120 val eVar = myListInterfaceType.arguments.single() 1121 eVar.assertReferencesTypeParameter(eParam) 1122 } 1123 } 1124 1125 @Test Test array of type with parameter used as type parameternull1126 fun `Test array of type with parameter used as type parameter`() { 1127 runCodebaseTest( 1128 signature( 1129 """ 1130 // Signature format: 2.0 1131 package test.pkg { 1132 public class Foo { 1133 method public java.util.Collection<java.util.List<java.lang.String>[]> foo(); 1134 } 1135 } 1136 """ 1137 .trimIndent() 1138 ), 1139 java( 1140 """ 1141 package test.pkg; 1142 1143 import java.util.Collection; 1144 import java.util.List; 1145 1146 public class Foo { 1147 public Collection<List<String>[]> foo() {} 1148 } 1149 """, 1150 ), 1151 kotlin( 1152 """ 1153 package test.pkg 1154 1155 class Foo { 1156 fun foo(): Collection<Array<List<String>>> {} 1157 } 1158 """ 1159 ) 1160 ) { 1161 val method = codebase.assertClass("test.pkg.Foo").methods().single() 1162 1163 // java.util.Collection<java.util.List<java.lang.String>[]> 1164 val collectionOfArrayOfStringList = method.returnType() 1165 assertThat(collectionOfArrayOfStringList).isInstanceOf(ClassTypeItem::class.java) 1166 assertThat((collectionOfArrayOfStringList as ClassTypeItem).qualifiedName) 1167 .isEqualTo("java.util.Collection") 1168 assertThat(collectionOfArrayOfStringList.arguments).hasSize(1) 1169 1170 // java.util.List<java.lang.String>[] 1171 val arrayOfStringList = collectionOfArrayOfStringList.arguments.single() 1172 assertThat(arrayOfStringList).isInstanceOf(ArrayTypeItem::class.java) 1173 1174 // java.util.List<java.lang.String> 1175 val stringList = (arrayOfStringList as ArrayTypeItem).componentType 1176 assertThat(stringList).isInstanceOf(ClassTypeItem::class.java) 1177 assertThat((stringList as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 1178 assertThat(stringList.arguments).hasSize(1) 1179 1180 // java.lang.String 1181 val string = stringList.arguments.single() 1182 assertThat(string.isString()).isTrue() 1183 } 1184 } 1185 1186 @Test Test Kotlin collection removeAll parameter typenull1187 fun `Test Kotlin collection removeAll parameter type`() { 1188 runCodebaseTest( 1189 kotlin( 1190 """ 1191 package test.pkg 1192 abstract class Foo<Z> : MutableCollection<Z> { 1193 override fun addAll(elements: Collection<Z>): Boolean = true 1194 override fun containsAll(elements: Collection<Z>): Boolean = true 1195 override fun removeAll(elements: Collection<Z>): Boolean = true 1196 override fun retainAll(elements: Collection<Z>): Boolean = true 1197 } 1198 """ 1199 ) 1200 ) { 1201 val fooClass = codebase.assertClass("test.pkg.Foo") 1202 val typeParam = fooClass.typeParameterList.single() 1203 1204 /** 1205 * Make sure that the [ClassItem] has a method whose single parameter is of the type 1206 * `java.lang.Collection` and then run [body] on that type. 1207 */ 1208 fun ClassItem.assertMethodTakesCollection( 1209 name: String, 1210 body: TypeArgumentTypeItem.() -> Unit 1211 ) { 1212 val method = methods().single { it.name() == name } 1213 val paramType = method.parameters().single().type() 1214 paramType.assertClassTypeItem { 1215 assertThat(qualifiedName).isEqualTo("java.util.Collection") 1216 assertThat(arguments).hasSize(1) 1217 val argument = arguments.single() 1218 argument.body() 1219 } 1220 } 1221 1222 /** 1223 * Make sure that the [ClassItem] has a method whose single parameter is of the type 1224 * `java.lang.Collection<? extends Z>`. 1225 */ 1226 fun ClassItem.assertMethodTakesCollectionWildcardExtendsZ(name: String) { 1227 assertMethodTakesCollection(name) { 1228 assertWildcardItem { extendsBound!!.assertReferencesTypeParameter(typeParam) } 1229 } 1230 } 1231 1232 // Defined in `java.util.Collection` as `addAll(Collection<? extends E> c)`. The type of 1233 // the `addAll` method in `Foo` should be `addAll(Collection<? extends Z>)`.Where `Z` 1234 // references the type parameter in `Foo<Z>`. 1235 fooClass.assertMethodTakesCollectionWildcardExtendsZ("addAll") 1236 1237 // Defined in `java.util.Collection` as `...(Collection<?> c)` these methods should be 1238 // `...(Collection<? extends Z>)`.Where `Z` references the type parameter in 1239 // `Foo<Z>`. 1240 // 1241 fooClass.assertMethodTakesCollectionWildcardExtendsZ("containsAll") 1242 fooClass.assertMethodTakesCollectionWildcardExtendsZ("removeAll") 1243 fooClass.assertMethodTakesCollectionWildcardExtendsZ("retainAll") 1244 } 1245 } 1246 1247 @Test Test convertTypenull1248 fun `Test convertType`() { 1249 runCodebaseTest( 1250 inputSet( 1251 java( 1252 """ 1253 package test.pkg; 1254 import java.util.List; 1255 import java.util.Map; 1256 public class Parent<M, N> { 1257 public M getM() {} 1258 public N[] getNArray() {} 1259 public List<M> getMList() {} 1260 public Map<M, N> getMap() {} 1261 public Parent<? extends M, ? super N> getWildcards() {} 1262 } 1263 """ 1264 .trimIndent() 1265 ), 1266 java( 1267 """ 1268 package test.pkg; 1269 public class Child<X, Y> extends Parent<X, Y> {} 1270 """ 1271 .trimIndent() 1272 ), 1273 ), 1274 inputSet( 1275 signature( 1276 """ 1277 // Signature format: 5.0 1278 package test.pkg { 1279 public class Child<X, Y> extends test.pkg.Parent<X,Y> { 1280 } 1281 public class Parent<M, N> { 1282 method public M getM(); 1283 method public java.util.List<M> getMList(); 1284 method public java.util.Map<M,N> getMap(); 1285 method public N[] getNArray(); 1286 method public test.pkg.Parent<? extends M, ? super N> getWildcards(); 1287 } 1288 } 1289 """ 1290 .trimIndent() 1291 ) 1292 ), 1293 inputSet( 1294 kotlin( 1295 """ 1296 package test.pkg 1297 open class Parent<M, N> { 1298 fun getM(): M {} 1299 fun getNArray(): Array<N> {} 1300 fun getMList(): List<M> {} 1301 fun getMap(): Map<M, N> {} 1302 fun getWildcards(): Parent<out M, in N> {} 1303 } 1304 class Child<X, Y> : Parent<X, Y>() 1305 """ 1306 .trimIndent() 1307 ) 1308 ) 1309 ) { 1310 val parent = codebase.assertClass("test.pkg.Parent") 1311 val child = codebase.assertClass("test.pkg.Child") 1312 val childTypeParams = child.typeParameterList 1313 val x = childTypeParams[0] 1314 val y = childTypeParams[1] 1315 1316 val mVar = parent.assertMethod("getM", "").returnType() 1317 val xVar = mVar.convertType(child, parent) 1318 assertThat(xVar.toTypeString()).isEqualTo("X") 1319 xVar.assertReferencesTypeParameter(x) 1320 1321 val nArray = parent.assertMethod("getNArray", "").returnType() 1322 val yArray = nArray.convertType(child, parent) 1323 assertThat(yArray.toTypeString()).isEqualTo("Y[]") 1324 assertThat((yArray as ArrayTypeItem).isVarargs).isFalse() 1325 yArray.componentType.assertReferencesTypeParameter(y) 1326 1327 val mList = parent.assertMethod("getMList", "").returnType() 1328 val xList = mList.convertType(child, parent) 1329 assertThat(xList.toTypeString()).isEqualTo("java.util.List<X>") 1330 assertThat((xList as ClassTypeItem).qualifiedName).isEqualTo("java.util.List") 1331 xList.arguments.single().assertReferencesTypeParameter(x) 1332 1333 val mToNMap = parent.assertMethod("getMap", "").returnType() 1334 val xToYMap = mToNMap.convertType(child, parent) 1335 assertThat(xToYMap.toTypeString()).isEqualTo("java.util.Map<X,Y>") 1336 assertThat((xToYMap as ClassTypeItem).qualifiedName).isEqualTo("java.util.Map") 1337 xToYMap.arguments[0].assertReferencesTypeParameter(x) 1338 xToYMap.arguments[1].assertReferencesTypeParameter(y) 1339 1340 val wildcards = parent.assertMethod("getWildcards", "").returnType() 1341 val convertedWildcards = wildcards.convertType(child, parent) 1342 assertThat(convertedWildcards.toTypeString()) 1343 .isEqualTo("test.pkg.Parent<? extends X,? super Y>") 1344 assertThat((convertedWildcards as ClassTypeItem).qualifiedName) 1345 .isEqualTo("test.pkg.Parent") 1346 assertThat(convertedWildcards.arguments).hasSize(2) 1347 1348 val extendsX = convertedWildcards.arguments[0] as WildcardTypeItem 1349 extendsX.extendsBound!!.assertReferencesTypeParameter(x) 1350 val superN = convertedWildcards.arguments[1] as WildcardTypeItem 1351 superN.superBound!!.assertReferencesTypeParameter(y) 1352 } 1353 } 1354 1355 @Test Test convertType with mapsnull1356 fun `Test convertType with maps`() { 1357 runCodebaseTest( 1358 java( 1359 """ 1360 package test.pkg; 1361 import java.util.List; 1362 public class Foo<T, X> { 1363 public Number numberType; 1364 1365 public int primitiveType; 1366 public int primitiveTypeAfterMatchingConversion; 1367 1368 public T variableType; 1369 public Number variableTypeAfterMatchingConversion; 1370 1371 public T[] arrayType; 1372 public Number[] arrayTypeAfterMatchingConversion; 1373 1374 public Foo<T, String> classType; 1375 public Foo<Number, String> classTypeAfterMatchingConversion; 1376 1377 public Foo<? extends T, String> wildcardExtendsType; 1378 public Foo<? extends Number, String> wildcardExtendsTypeAfterMatchingConversion; 1379 1380 public Foo<? super T, String> wildcardSuperType; 1381 public Foo<? super Number, String> wildcardSuperTypeAfterMatchingConversion; 1382 } 1383 """ 1384 .trimIndent() 1385 ), 1386 kotlin( 1387 """ 1388 package test.pkg 1389 class Foo<T, X> { 1390 @JvmField val numberType: Number 1391 1392 @JvmField val primitiveType: Int 1393 @JvmField val primitiveTypeAfterMatchingConversion: Int 1394 1395 @JvmField val variableType: T 1396 @JvmField val variableTypeAfterMatchingConversion: Number 1397 1398 @JvmField val arrayType: Array<T> 1399 @JvmField val arrayTypeAfterMatchingConversion: Array<Number> 1400 1401 @JvmField val classType: Foo<T, String> 1402 @JvmField val classTypeAfterMatchingConversion: Foo<Number, String> 1403 1404 @JvmField val wildcardExtendsType: Foo<out T, String> 1405 @JvmField val wildcardExtendsTypeAfterMatchingConversion: Foo<out Number, String> 1406 1407 @JvmField val wildcardSuperType: Foo<in T, String> 1408 @JvmField val wildcardSuperTypeAfterMatchingConversion: Foo<in Number, String> 1409 } 1410 """ 1411 .trimIndent() 1412 ), 1413 signature( 1414 """ 1415 // Signature format: 5.0 1416 package test.pkg { 1417 public class Foo<T, X> { 1418 field public Number numberType; 1419 1420 field public int primitiveType; 1421 field public int primitiveTypeAfterMatchingConversion; 1422 1423 field public T variableType; 1424 field public Number variableTypeAfterMatchingConversion; 1425 1426 field public T[] arrayType; 1427 field public Number[] arrayTypeAfterMatchingConversion; 1428 1429 field public test.pkg.Foo<T, String> classType; 1430 field public test.pkg.Foo<Number, String> classTypeAfterMatchingConversion; 1431 1432 field public test.pkg.Foo<? extends T, String> wildcardExtendsType; 1433 field public test.pkg.Foo<? extends Number, String> wildcardExtendsTypeAfterMatchingConversion; 1434 1435 field public test.pkg.Foo<? super T, String> wildcardSuperType; 1436 field public test.pkg.Foo<? super Number, String> wildcardSuperTypeAfterMatchingConversion; 1437 } 1438 } 1439 """ 1440 .trimIndent() 1441 ) 1442 ) { 1443 val fooClass = codebase.assertClass("test.pkg.Foo") 1444 val t = fooClass.typeParameterList.single { it.name() == "T" } 1445 val x = fooClass.typeParameterList.single { it.name() == "X" } 1446 val numberType = fooClass.assertField("numberType").type() as ReferenceTypeItem 1447 1448 val matchingBindings = mapOf(t to numberType) 1449 val nonMatchingBindings = mapOf(x to numberType) 1450 1451 val afterMatchingConversionSuffix = "AfterMatchingConversion" 1452 val fieldsToCheck = 1453 fooClass.fields().filter { 1454 it.name() != "numberType" && !it.name().endsWith(afterMatchingConversionSuffix) 1455 } 1456 1457 for (fieldItem in fieldsToCheck) { 1458 val fieldType = fieldItem.type() 1459 1460 val fieldName = fieldItem.name() 1461 val expectedMatchedFieldType = 1462 fooClass.assertField(fieldName + afterMatchingConversionSuffix).type() 1463 1464 assertWithMessage("conversion that matches $fieldName") 1465 .that(fieldType.convertType(matchingBindings)) 1466 .isEqualTo(expectedMatchedFieldType) 1467 1468 // Expect no change if it does not match. 1469 assertWithMessage("conversion that does not match $fieldName") 1470 .that(fieldType.convertType(nonMatchingBindings)) 1471 .isEqualTo(fieldType) 1472 } 1473 } 1474 } 1475 1476 @Test Test hasTypeArgumentsnull1477 fun `Test hasTypeArguments`() { 1478 runCodebaseTest( 1479 java( 1480 """ 1481 package test.pkg; 1482 public abstract class Foo implements Comparable<String> {} 1483 """ 1484 ), 1485 kotlin( 1486 """ 1487 package test.pkg 1488 abstract class Foo: Comparable<String> 1489 """ 1490 ), 1491 signature( 1492 """ 1493 // Signature format: 2.0 1494 package test.pkg { 1495 public abstract class Foo implements Comparable<String> {} 1496 } 1497 """ 1498 ), 1499 ) { 1500 val classType = codebase.assertClass("test.pkg.Foo").type() 1501 assertThat(classType.hasTypeArguments()).isFalse() 1502 1503 val interfaceType = codebase.assertClass("test.pkg.Foo").interfaceTypes().single() 1504 assertThat(interfaceType.hasTypeArguments()).isTrue() 1505 } 1506 } 1507 } 1508