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.propertyitem 18 19 import com.android.tools.metalava.model.PrimitiveTypeItem 20 import com.android.tools.metalava.model.PropertyItem 21 import com.android.tools.metalava.model.testing.testTypeString 22 import com.android.tools.metalava.model.testsuite.BaseModelTest 23 import com.android.tools.metalava.testing.kotlin 24 import com.google.common.truth.Truth.assertThat 25 import kotlin.test.assertNull 26 import kotlin.test.assertTrue 27 import org.junit.Assert.assertEquals 28 import org.junit.Test 29 30 /** Common tests for implementations of [PropertyItem]. */ 31 class CommonPropertyItemTest : BaseModelTest() { 32 33 @Test Test access type parameter of outer classnull34 fun `Test access type parameter of outer class`() { 35 runCodebaseTest( 36 signature( 37 """ 38 // Signature format: 2.0 39 package test.pkg { 40 public class Outer<O> { 41 } 42 public class Outer.Middle { 43 } 44 public abstract class Outer.Middle.Inner { 45 property public abstract O property; 46 } 47 } 48 """ 49 ), 50 kotlin( 51 """ 52 package test.pkg 53 54 class Outer<O> private constructor() { 55 inner class Middle private constructor() { 56 abstract inner class Inner private constructor() { 57 abstract val property: O 58 } 59 } 60 } 61 """ 62 ), 63 ) { 64 val oTypeParameter = codebase.assertClass("test.pkg.Outer").typeParameterList.single() 65 val propertyType = 66 codebase 67 .assertClass("test.pkg.Outer.Middle.Inner") 68 .assertProperty("property") 69 .type() 70 71 propertyType.assertReferencesTypeParameter(oTypeParameter) 72 } 73 } 74 75 @Test Test deprecated getter and setter by annotationnull76 fun `Test deprecated getter and setter by annotation`() { 77 runCodebaseTest( 78 kotlin( 79 """ 80 package test.pkg 81 82 class Bar { 83 private var fooImpl: String = "" 84 @Deprecated("blah") 85 var foo: String 86 get() = fooImpl 87 @Deprecated("blah") 88 set(value) {fooImpl = value} 89 } 90 """ 91 ), 92 ) { 93 val barClass = codebase.assertClass("test.pkg.Bar") 94 val property = barClass.assertProperty("foo") 95 val methods = barClass.methods() 96 val getter = methods.single { it.name() == "getFoo" } 97 val setter = methods.single { it.name() == "setFoo" } 98 assertEquals("property originallyDeprecated", true, property.originallyDeprecated) 99 assertEquals("getter originallyDeprecated", true, getter.originallyDeprecated) 100 assertEquals("setter originallyDeprecated", true, setter.originallyDeprecated) 101 } 102 } 103 104 @Test Test property delegate to Kotlin objectnull105 fun `Test property delegate to Kotlin object`() { 106 runCodebaseTest( 107 kotlin( 108 """ 109 package test.pkg 110 import kotlin.properties.ReadOnlyProperty 111 import kotlin.reflect.KProperty 112 class Foo { 113 val field: String by object : ReadOnlyProperty<Foo, String> { 114 fun getValue(thisRef: T, property: KProperty<*>) = "foo" 115 } 116 } 117 """ 118 ), 119 // No signature file as it does not care about field values that are not constant 120 // literals. 121 ) { 122 val fooClass = codebase.assertClass("test.pkg.Foo") 123 val fieldType = fooClass.fields().single().type() 124 fieldType.assertClassTypeItem { 125 // The type of the field is NOT `String` (that is the type of the property). The 126 // type of the field is the property delegate. 127 assertThat(qualifiedName).isEqualTo("kotlin.properties.ReadOnlyProperty") 128 } 129 130 val propertyType = fooClass.properties().single().type() 131 propertyType.assertClassTypeItem { 132 assertThat(qualifiedName).isEqualTo("java.lang.String") 133 } 134 } 135 } 136 137 @Test Test property delegate to generic Kotlin objectnull138 fun `Test property delegate to generic Kotlin object`() { 139 runCodebaseTest( 140 kotlin( 141 """ 142 package test.pkg 143 val targetList: List<String?> = emptyList() 144 class Foo { 145 val delegatingList by ::targetList 146 } 147 """ 148 ), 149 ) { 150 val fooClass = codebase.assertClass("test.pkg.Foo") 151 val fieldItem = fooClass.fields().single() 152 assertThat(fieldItem.name()).isEqualTo("delegatingList\$delegate") 153 val fieldType = fieldItem.type() 154 fieldType.assertClassTypeItem { 155 assertThat(testTypeString(kotlinStyleNulls = true)) 156 .isEqualTo( 157 "kotlin.reflect.KProperty0<? extends java.util.List<? extends java.lang.String?>>" 158 ) 159 } 160 161 val propertyItem = fooClass.properties().single() 162 assertThat(propertyItem.name()).isEqualTo("delegatingList") 163 val propertyType = propertyItem.type() 164 propertyType.assertClassTypeItem { 165 assertThat(testTypeString(kotlinStyleNulls = true)) 166 .isEqualTo("java.util.List<java.lang.String?>") 167 } 168 } 169 } 170 171 @Test Test property delegate to lambda Kotlin objectnull172 fun `Test property delegate to lambda Kotlin object`() { 173 runCodebaseTest( 174 kotlin( 175 """ 176 package test.pkg 177 val targetList: (Int, String?) -> Boolean = {} 178 class Foo { 179 val delegatingList by ::targetList 180 } 181 """ 182 ), 183 ) { 184 val fooClass = codebase.assertClass("test.pkg.Foo") 185 val fieldItem = fooClass.fields().single() 186 assertThat(fieldItem.name()).isEqualTo("delegatingList\$delegate") 187 val fieldType = fieldItem.type() 188 fieldType.assertClassTypeItem { 189 assertThat(testTypeString(kotlinStyleNulls = true)) 190 .isEqualTo( 191 "kotlin.reflect.KProperty0<? extends kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String?,? extends java.lang.Boolean>>" 192 ) 193 } 194 195 val propertyItem = fooClass.properties().single() 196 assertThat(propertyItem.name()).isEqualTo("delegatingList") 197 val propertyType = propertyItem.type() 198 propertyType.assertClassTypeItem { 199 assertThat(testTypeString(kotlinStyleNulls = true)) 200 .isEqualTo( 201 "kotlin.jvm.functions.Function2<java.lang.Integer,java.lang.String?,java.lang.Boolean>" 202 ) 203 } 204 } 205 } 206 207 @Test Test abstract property of non-null stringnull208 fun `Test abstract property of non-null string`() { 209 runCodebaseTest( 210 kotlin( 211 """ 212 package test.pkg 213 class Foo { 214 val property: String 215 get() = "" 216 } 217 """ 218 ), 219 ) { 220 val fooClass = codebase.assertClass("test.pkg.Foo") 221 val propertyType = fooClass.properties().single().type() 222 propertyType.assertClassTypeItem { 223 assertThat(testTypeString(kotlinStyleNulls = true)).isEqualTo("java.lang.String") 224 } 225 226 val getter = fooClass.methods().single() 227 assertThat(getter.kotlinLikeDescription()) 228 .isEqualTo("fun getProperty(): java.lang.String") 229 } 230 } 231 232 @Test Test abstract property of nullable stringnull233 fun `Test abstract property of nullable string`() { 234 runCodebaseTest( 235 kotlin( 236 """ 237 package test.pkg 238 class Foo { 239 val property: String? 240 get() = null 241 } 242 """ 243 ), 244 ) { 245 val fooClass = codebase.assertClass("test.pkg.Foo") 246 val propertyType = fooClass.properties().single().type() 247 propertyType.assertClassTypeItem { 248 assertThat(testTypeString(kotlinStyleNulls = true)).isEqualTo("java.lang.String?") 249 } 250 251 val getter = fooClass.methods().single() 252 assertThat(getter.kotlinLikeDescription()) 253 .isEqualTo("fun getProperty(): java.lang.String?") 254 } 255 } 256 257 @Test Test abstract property of list of non-null stringnull258 fun `Test abstract property of list of non-null string`() { 259 runCodebaseTest( 260 kotlin( 261 """ 262 package test.pkg 263 class Foo { 264 val property: List<String> 265 get() = emptyList() 266 } 267 """ 268 ), 269 ) { 270 val fooClass = codebase.assertClass("test.pkg.Foo") 271 val propertyType = fooClass.properties().single().type() 272 propertyType.assertClassTypeItem { 273 assertThat(testTypeString(kotlinStyleNulls = true)) 274 .isEqualTo("java.util.List<java.lang.String>") 275 } 276 277 val getter = fooClass.methods().single() 278 assertThat(getter.kotlinLikeDescription()) 279 .isEqualTo("fun getProperty(): java.util.List<java.lang.String>") 280 } 281 } 282 283 @Test Test abstract property of list of nullable stringnull284 fun `Test abstract property of list of nullable string`() { 285 runCodebaseTest( 286 kotlin( 287 """ 288 package test.pkg 289 class Foo { 290 val property: List<String?> 291 get() = emptyList() 292 } 293 """ 294 ), 295 ) { 296 val fooClass = codebase.assertClass("test.pkg.Foo") 297 val propertyType = fooClass.properties().single().type() 298 propertyType.assertClassTypeItem { 299 assertThat(testTypeString(kotlinStyleNulls = true)) 300 .isEqualTo("java.util.List<java.lang.String?>") 301 } 302 303 val getter = fooClass.methods().single() 304 assertThat(getter.kotlinLikeDescription()) 305 .isEqualTo("fun getProperty(): java.util.List<java.lang.String?>") 306 } 307 } 308 309 @Test Test abstract mutable property of non-null stringnull310 fun `Test abstract mutable property of non-null string`() { 311 runCodebaseTest( 312 kotlin( 313 """ 314 package test.pkg 315 class Foo { 316 var property: String 317 get() = "" 318 set(value) {field = value} 319 } 320 """ 321 ), 322 ) { 323 val fooClass = codebase.assertClass("test.pkg.Foo") 324 val propertyType = fooClass.properties().single().type() 325 propertyType.assertClassTypeItem { 326 assertThat(testTypeString(kotlinStyleNulls = true)).isEqualTo("java.lang.String") 327 } 328 329 val methods = 330 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 331 assertThat(methods) 332 .isEqualTo( 333 """ 334 fun getProperty(): java.lang.String 335 fun setProperty(value: java.lang.String): void 336 """ 337 .trimIndent() 338 ) 339 } 340 } 341 342 @Test Test abstract mutable property of nullable stringnull343 fun `Test abstract mutable property of nullable string`() { 344 runCodebaseTest( 345 kotlin( 346 """ 347 package test.pkg 348 class Foo { 349 var property: String? 350 get() = null 351 set(value) {field = value} 352 } 353 """ 354 ), 355 ) { 356 val fooClass = codebase.assertClass("test.pkg.Foo") 357 val propertyType = fooClass.properties().single().type() 358 propertyType.assertClassTypeItem { 359 assertThat(testTypeString(kotlinStyleNulls = true)).isEqualTo("java.lang.String?") 360 } 361 362 val methods = 363 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 364 assertThat(methods) 365 .isEqualTo( 366 """ 367 fun getProperty(): java.lang.String? 368 fun setProperty(value: java.lang.String?): void 369 """ 370 .trimIndent() 371 ) 372 } 373 } 374 375 @Test Test abstract mutable property of list of non-null stringnull376 fun `Test abstract mutable property of list of non-null string`() { 377 runCodebaseTest( 378 kotlin( 379 """ 380 package test.pkg 381 class Foo { 382 var property: List<String> 383 get() = emptyList() 384 set(value) {field = value} 385 } 386 """ 387 ), 388 ) { 389 val fooClass = codebase.assertClass("test.pkg.Foo") 390 val propertyType = fooClass.properties().single().type() 391 propertyType.assertClassTypeItem { 392 assertThat(testTypeString(kotlinStyleNulls = true)) 393 .isEqualTo("java.util.List<java.lang.String>") 394 } 395 396 val methods = 397 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 398 assertThat(methods) 399 .isEqualTo( 400 """ 401 fun getProperty(): java.util.List<java.lang.String> 402 fun setProperty(value: java.util.List<java.lang.String>): void 403 """ 404 .trimIndent() 405 ) 406 } 407 } 408 409 @Test Test abstract mutable property of list of nullable stringnull410 fun `Test abstract mutable property of list of nullable string`() { 411 runCodebaseTest( 412 kotlin( 413 """ 414 package test.pkg 415 class Foo { 416 var property: List<String?> 417 get() = emptyList() 418 set(value) {field = value} 419 } 420 """ 421 ), 422 ) { 423 val fooClass = codebase.assertClass("test.pkg.Foo") 424 val propertyType = fooClass.properties().single().type() 425 propertyType.assertClassTypeItem { 426 assertThat(testTypeString(kotlinStyleNulls = true)) 427 .isEqualTo("java.util.List<java.lang.String?>") 428 } 429 430 val methods = 431 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 432 assertThat(methods) 433 .isEqualTo( 434 """ 435 fun getProperty(): java.util.List<java.lang.String?> 436 fun setProperty(value: java.util.List<java.lang.String?>): void 437 """ 438 .trimIndent() 439 ) 440 } 441 } 442 443 @Test Test mutable non-null generic property overriding property exposing public setternull444 fun `Test mutable non-null generic property overriding property exposing public setter`() { 445 runCodebaseTest( 446 kotlin( 447 """ 448 package test.pkg 449 450 abstract class Baz<T> { 451 abstract var property: T 452 internal set 453 } 454 455 class Foo<T>(initialValue: T) : Baz<T> { 456 override var property: T = initialValue 457 public set 458 } 459 """ 460 ), 461 ) { 462 val fooClass = codebase.assertClass("test.pkg.Foo") 463 464 val methods = 465 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 466 assertThat(methods) 467 .isEqualTo( 468 """ 469 fun getProperty(): T 470 fun setProperty(<set-?>: T): void 471 """ 472 .trimIndent() 473 ) 474 } 475 } 476 477 @Test Test mutable nullable generic property overriding property exposing public setternull478 fun `Test mutable nullable generic property overriding property exposing public setter`() { 479 runCodebaseTest( 480 kotlin( 481 """ 482 package test.pkg 483 484 abstract class Baz<T> { 485 abstract var property: T? 486 internal set 487 } 488 489 class Foo<T> : Baz<T> { 490 override var property: T? = null 491 public set 492 } 493 """ 494 ), 495 ) { 496 val fooClass = codebase.assertClass("test.pkg.Foo") 497 498 val methods = 499 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 500 assertThat(methods) 501 .isEqualTo( 502 """ 503 fun getProperty(): T? 504 fun setProperty(<set-?>: T?): void 505 """ 506 .trimIndent() 507 ) 508 } 509 } 510 511 @Test Test mutable list of nullable property overriding property exposing public setternull512 fun `Test mutable list of nullable property overriding property exposing public setter`() { 513 runCodebaseTest( 514 kotlin( 515 """ 516 package test.pkg 517 518 abstract class Baz { 519 abstract var property: List<String?> 520 internal set 521 } 522 523 class Foo : Baz<T> { 524 override var property: List<String?> = emptyList() 525 public set 526 } 527 """ 528 ), 529 ) { 530 val fooClass = codebase.assertClass("test.pkg.Foo") 531 532 val methods = 533 fooClass.methods().map { it.kotlinLikeDescription() }.sorted().joinToString("\n") 534 assertThat(methods) 535 .isEqualTo( 536 """ 537 fun getProperty(): java.util.List<java.lang.String?> 538 fun setProperty(<set-?>: java.util.List<java.lang.String?>): void 539 """ 540 .trimIndent() 541 ) 542 } 543 } 544 545 @Test Test companion propertynull546 fun `Test companion property`() { 547 runCodebaseTest( 548 kotlin( 549 """ 550 package test.pkg 551 class Foo { 552 companion object { 553 val value: Int = 0 554 const val constant: Int = 1 555 @JvmField val jvmField: Int = 2 556 } 557 } 558 """ 559 ) 560 ) { 561 val foo = codebase.assertClass("test.pkg.Foo") 562 assertThat(foo.methods()).isEmpty() 563 assertThat(foo.properties()).isEmpty() 564 foo.assertField("constant") 565 foo.assertField("jvmField") 566 567 val fooCompanion = codebase.assertClass("test.pkg.Foo.Companion") 568 assertThat(fooCompanion.fields()).isEmpty() 569 assertThat(fooCompanion.methods()).hasSize(1) 570 val valueGetterOnCompanion = fooCompanion.assertMethod("getValue", "") 571 572 assertThat(fooCompanion.properties()).hasSize(3) 573 val constantPropertyOnCompanion = fooCompanion.assertProperty("constant") 574 val jvmPropertyOnCompanion = fooCompanion.assertProperty("jvmField") 575 val valuePropertyOnCompanion = fooCompanion.assertProperty("value") 576 577 assertThat(jvmPropertyOnCompanion.getter).isNull() 578 assertThat(constantPropertyOnCompanion.getter).isNull() 579 assertThat(valuePropertyOnCompanion.getter).isEqualTo(valueGetterOnCompanion) 580 } 581 } 582 583 @Test Test top level propertiesnull584 fun `Test top level properties`() { 585 runCodebaseTest( 586 kotlin( 587 """ 588 @file:JvmName("Foo") 589 package test.pkg 590 591 var variable = 0 592 593 val valWithNoBackingField 594 get() = 0 595 596 const val CONST = 0 597 598 @JvmField 599 val jvmField = 0 600 """ 601 ) 602 ) { 603 val fileFacadeClass = codebase.assertClass("test.pkg.Foo") 604 assertThat(fileFacadeClass.properties()).hasSize(4) 605 606 // var property with getter, setter, and backing field 607 val variable = fileFacadeClass.assertProperty("variable") 608 assertThat(variable.getter).isNotNull() 609 assertThat(variable.setter).isNotNull() 610 assertThat(variable.backingField).isNotNull() 611 assertThat(variable.constructorParameter).isNull() 612 613 // val property with getter, no setter or backing field 614 val valWithNoBackingField = fileFacadeClass.assertProperty("valWithNoBackingField") 615 assertThat(valWithNoBackingField.getter).isNotNull() 616 assertThat(valWithNoBackingField.setter).isNull() 617 assertThat(valWithNoBackingField.backingField).isNull() 618 assertThat(valWithNoBackingField.constructorParameter).isNull() 619 620 // const val doesn't have accessors, but does have backing field 621 val constVal = fileFacadeClass.assertProperty("CONST") 622 assertThat(constVal.getter).isNull() 623 assertThat(constVal.setter).isNull() 624 assertThat(constVal.backingField).isNotNull() 625 assertThat(constVal.constructorParameter).isNull() 626 627 // jvmfield val doesn't have accessors, but does have backing field 628 val jvmField = fileFacadeClass.assertProperty("jvmField") 629 assertThat(jvmField.getter).isNull() 630 assertThat(jvmField.setter).isNull() 631 assertThat(jvmField.backingField).isNotNull() 632 assertThat(jvmField.constructorParameter).isNull() 633 } 634 } 635 636 @Test Test top level extension propertiesnull637 fun `Test top level extension properties`() { 638 runCodebaseTest( 639 kotlin( 640 """ 641 @file:JvmName("Foo") 642 package test.pkg 643 644 var String.stringExtension 645 get() = 0 646 set(value) {} 647 """ 648 ) 649 ) { 650 val fileFacadeClass = codebase.assertClass("test.pkg.Foo") 651 assertThat(fileFacadeClass.properties()).hasSize(1) 652 653 // extension property has getter and setter, but no backing field 654 val stringExtension = fileFacadeClass.assertProperty("stringExtension") 655 assertThat(stringExtension.getter).isNotNull() 656 assertThat(stringExtension.setter).isNotNull() 657 assertThat(stringExtension.backingField).isNull() 658 assertThat(stringExtension.constructorParameter).isNull() 659 } 660 } 661 662 @Test Value class extension propertiesnull663 fun `Value class extension properties`() { 664 runCodebaseTest( 665 kotlin( 666 """ 667 @file:JvmName("Foo") 668 package test.pkg 669 670 value class IntValue(val value: Int) 671 672 var IntValue.valueClassExtension 673 get() = 0 674 set(value) {} 675 """ 676 ) 677 ) { 678 val fileFacadeClass = codebase.assertClass("test.pkg.Foo") 679 assertThat(fileFacadeClass.properties()).hasSize(1) 680 681 // extension property has getter and setter, but no backing field 682 val valueClassExtension = fileFacadeClass.assertProperty("valueClassExtension") 683 assertThat(valueClassExtension.getter).isNotNull() 684 assertThat(valueClassExtension.setter).isNotNull() 685 assertThat(valueClassExtension.backingField).isNull() 686 assertThat(valueClassExtension.constructorParameter).isNull() 687 688 // the extension property receiver is a value class type, which gets mapped to its 689 // value type 690 valueClassExtension.receiver.assertPrimitiveTypeItem { 691 assertEquals(kind, PrimitiveTypeItem.Primitive.INT) 692 } 693 } 694 } 695 Test final modifier for propertiesnull696 fun `Test final modifier for properties`() { 697 runCodebaseTest( 698 kotlin( 699 """ 700 package test.pkg 701 class FinalClass { 702 val propertyInFinalClass = 0 703 } 704 """ 705 ), 706 kotlin( 707 """ 708 package test.pkg 709 open class OpenClass { 710 val finalPropertyInOpenClass = 0 711 open val openPropertyInOpenClass = 0 712 } 713 """ 714 ) 715 ) { 716 val finalClass = codebase.assertClass("test.pkg.FinalClass") 717 assertThat(finalClass.modifiers.isFinal()).isTrue() 718 // Properties in final classes are final, so using the modifier would be redundant. 719 assertThat(finalClass.assertProperty("propertyInFinalClass").modifiers.isFinal()) 720 .isFalse() 721 722 val openClass = codebase.assertClass("test.pkg.OpenClass") 723 assertThat(openClass.modifiers.isFinal()).isFalse() 724 assertThat(openClass.assertProperty("finalPropertyInOpenClass").modifiers.isFinal()) 725 .isTrue() 726 assertThat(openClass.assertProperty("openPropertyInOpenClass").modifiers.isFinal()) 727 .isFalse() 728 } 729 } 730 731 @Test JvmStatic property in object is staticnull732 fun `JvmStatic property in object is static`() { 733 runCodebaseTest( 734 kotlin( 735 """ 736 package test.pkg 737 import kotlin.jvm.JvmStatic 738 object Foo { 739 @JvmStatic 740 val jvmStaticProperty = 0 741 val notStaticProperty = 0 742 } 743 """ 744 ) 745 ) { 746 val fooClass = codebase.assertClass("test.pkg.Foo") 747 val jvmStaticProperty = fooClass.assertProperty("jvmStaticProperty") 748 assertThat(jvmStaticProperty.modifiers.isStatic()).isTrue() 749 val notStaticProperty = fooClass.assertProperty("notStaticProperty") 750 assertThat(notStaticProperty.modifiers.isStatic()).isFalse() 751 } 752 } 753 754 @Test Test abstract and default modifier on propertiesnull755 fun `Test abstract and default modifier on properties`() { 756 runCodebaseTest( 757 kotlin( 758 """ 759 package test.pkg 760 761 interface Interface { 762 // interface properties cannot have initializers 763 // if no getter is defined, the property is abstract 764 val abstractVal: Int 765 // getter is defined, the property is default 766 val defaultVal: Int 767 get() = 0 768 769 companion object { 770 // this shouldn't be default because the immediate container is an 771 // object, not an interface 772 val interfaceCompanionValWithGetter: Int 773 get() = 0 774 } 775 } 776 777 abstract class AbstractClass { 778 abstract val abstractVal: Int 779 780 val nonAbstractValWithInitializer: Int = 0 781 val nonAbstractValWithGetter: Int 782 get() = 0 783 784 // lateinit cannot be paired with abstract 785 lateinit var nonAbstractLateinitVar: String 786 787 val notAbstractValInInitBlock: Int 788 init { 789 notAbstractValInInitBlock = 0 790 } 791 } 792 """ 793 ) 794 ) { 795 val interfaceClass = codebase.assertClass("test.pkg.Interface") 796 val abstractInterfaceProperty = interfaceClass.assertProperty("abstractVal") 797 assertThat(abstractInterfaceProperty.modifiers.isAbstract()).isTrue() 798 assertThat(abstractInterfaceProperty.modifiers.isDefault()).isFalse() 799 val defaultInterfaceProperty = interfaceClass.assertProperty("defaultVal") 800 assertThat(defaultInterfaceProperty.modifiers.isAbstract()).isFalse() 801 assertThat(defaultInterfaceProperty.modifiers.isDefault()).isTrue() 802 803 val interfaceCompanion = interfaceClass.nestedClasses().single() 804 val interfaceCompanionProperty = 805 interfaceCompanion.assertProperty("interfaceCompanionValWithGetter") 806 assertThat(interfaceCompanionProperty.modifiers.isAbstract()).isFalse() 807 assertThat(interfaceCompanionProperty.modifiers.isDefault()).isFalse() 808 809 val abstractClass = codebase.assertClass("test.pkg.AbstractClass") 810 val abstractClassProperty = abstractClass.assertProperty("abstractVal") 811 assertThat(abstractClassProperty.modifiers.isAbstract()).isTrue() 812 assertThat(abstractClassProperty.modifiers.isDefault()).isFalse() 813 814 val nonAbstractPropertiesFromAbstractClass = 815 listOf( 816 abstractClass.assertProperty("nonAbstractValWithInitializer"), 817 abstractClass.assertProperty("nonAbstractValWithGetter"), 818 abstractClass.assertProperty("nonAbstractLateinitVar"), 819 abstractClass.assertProperty("notAbstractValInInitBlock"), 820 ) 821 822 for (property in nonAbstractPropertiesFromAbstractClass) { 823 assertThat(property.modifiers.isAbstract()).isFalse() 824 assertThat(property.modifiers.isDefault()).isFalse() 825 } 826 } 827 } 828 829 @Test Test property receiversnull830 fun `Test property receivers`() { 831 runCodebaseTest( 832 kotlin( 833 """ 834 @file:JvmName("Foo") 835 package test.pkg 836 val noReceiverProperty = 0 837 // Extension properties can't have backing fields, so they need defined getters 838 val Int.intProperty 839 get() = 0 840 val String.stringProperty 841 get() = 0 842 val Array<String>.stringArrayProperty 843 get() = 0 844 val List<String>.stringListProperty 845 get() = 0 846 """ 847 ), 848 // Skip getters in the signature file since they aren't important to the test 849 signature( 850 """ 851 // Signature format: 5.0 852 package test.pkg { 853 public final class Foo { 854 property public static int noReceiverProperty; 855 property public static int int.intProperty; 856 property public static int String.stringProperty; 857 property public static int String[].stringArrayProperty; 858 property public static int java.util.List<? extends String>.stringListProperty; 859 } 860 } 861 """ 862 ), 863 signature( 864 """ 865 // Signature format: 5.0 866 // - kotlin-name-type-order=yes 867 package test.pkg { 868 public final class Foo { 869 property public static noReceiverProperty: int; 870 property public static int.intProperty: int; 871 property public static String.stringProperty: int; 872 property public static String[].stringArrayProperty: int; 873 property public static java.util.List<? extends String>.stringListProperty: int; 874 } 875 } 876 """ 877 ) 878 ) { 879 val fooClass = codebase.assertClass("test.pkg.Foo") 880 881 assertNull(fooClass.assertProperty("noReceiverProperty").receiver) 882 883 fooClass.assertProperty("intProperty").receiver.assertPrimitiveTypeItem { 884 assertEquals(kind, PrimitiveTypeItem.Primitive.INT) 885 } 886 887 fooClass.assertProperty("stringProperty").receiver.assertClassTypeItem { 888 assertTrue(isString()) 889 } 890 891 fooClass.assertProperty("stringArrayProperty").receiver.assertArrayTypeItem { 892 componentType.assertClassTypeItem { assertTrue(isString()) } 893 } 894 895 fooClass.assertProperty("stringListProperty").receiver.assertClassTypeItem { 896 assertEquals(qualifiedName, "java.util.List") 897 arguments.single().assertWildcardItem { 898 extendsBound.assertClassTypeItem { assertTrue(isString()) } 899 } 900 } 901 } 902 } 903 904 @Test Test property type parameters, receiver typesnull905 fun `Test property type parameters, receiver types`() { 906 runCodebaseTest( 907 kotlin( 908 """ 909 @file:JvmName("Foo") 910 package test.pkg 911 val String.noTypeParameterProperty = 0 912 // Property type parameters must be used in the receiver type 913 // Extension properties can't have backing fields, so they need defined getters 914 val <T> T.oneTypeParameterReceiver 915 get() = 0 916 val <T> List<T>.oneTypeParameterListReceiver 917 get() = 0 918 val <T : String> T.oneTypeParameterWithBoundsReceiver 919 get() = 0 920 val <T1, T2> Map<T1, T2>.twoTypeParameterMapReceiver 921 get() = 0 922 val <T1 : String, T2 : List<T1>> Map<T1, T2>.twoTypeParameterWithBoundsMapReceiver 923 get() = 0 924 """ 925 ), 926 // Skip getters in the signature file since they aren't important to the test 927 signature( 928 """ 929 // Signature format: 5.0 930 package test.pkg { 931 public final class Foo { 932 property public static int String.noTypeParameterProperty; 933 property public static <T> int T.oneTypeParameterReceiver; 934 property public static <T> int java.util.List<? extends T>.oneTypeParameterListReceiver; 935 property public static <T extends String> int T.oneTypeParameterWithBoundsReceiver; 936 property public static <T1, T2> int java.util.Map<T1,? extends T2>.twoTypeParameterMapReceiver; 937 property public static <T1 extends String, T2 extends java.util.List<? extends T1>> int java.util.Map<T1,? extends T2>.twoTypeParameterWithBoundsMapReceiver; 938 } 939 } 940 """ 941 ), 942 signature( 943 """ 944 // Signature format: 5.0 945 // - kotlin-name-type-order=yes 946 package test.pkg { 947 public final class Foo { 948 property public static String.noTypeParameterProperty: int; 949 property public static <T> T.oneTypeParameterReceiver: int; 950 property public static <T> java.util.List<? extends T>.oneTypeParameterListReceiver: int; 951 property public static <T extends String> T.oneTypeParameterWithBoundsReceiver: int; 952 property public static <T1, T2> java.util.Map<T1,? extends T2>.twoTypeParameterMapReceiver: int; 953 property public static <T1 extends String, T2 extends java.util.List<? extends T1>> java.util.Map<T1,? extends T2>.twoTypeParameterWithBoundsMapReceiver: int; 954 } 955 } 956 """ 957 ), 958 ) { 959 val fooClass = codebase.assertClass("test.pkg.Foo") 960 961 val noTypeParameterProperty = fooClass.assertProperty("noTypeParameterProperty") 962 assertThat(noTypeParameterProperty.typeParameterList).isEmpty() 963 964 // val <T> T.oneTypeParameterReceiver 965 val oneTypeParameterReceiver = fooClass.assertProperty("oneTypeParameterReceiver") 966 val oneTypeParameterReceiverT = oneTypeParameterReceiver.typeParameterList.single() 967 assertThat(oneTypeParameterReceiverT.name()).isEqualTo("T") 968 assertThat(oneTypeParameterReceiverT.typeBounds()).isEmpty() 969 assertThat(oneTypeParameterReceiverT.isReified()).isFalse() 970 oneTypeParameterReceiver.receiver.assertVariableTypeItem { 971 assertEquals(asTypeParameter, oneTypeParameterReceiverT) 972 } 973 974 // val <T> List<T>.oneTypeParameterListReceiver 975 val oneTypeParameterListReceiver = 976 fooClass.assertProperty("oneTypeParameterListReceiver") 977 val oneTypeParameterListReceiverT = 978 oneTypeParameterListReceiver.typeParameterList.single() 979 assertThat(oneTypeParameterListReceiverT.name()).isEqualTo("T") 980 assertThat(oneTypeParameterListReceiverT.typeBounds()).isEmpty() 981 assertThat(oneTypeParameterListReceiverT.isReified()).isFalse() 982 oneTypeParameterListReceiver.receiver.assertClassTypeItem { 983 assertEquals(qualifiedName, "java.util.List") 984 arguments.single().assertWildcardItem { 985 extendsBound.assertVariableTypeItem { 986 assertEquals(asTypeParameter, oneTypeParameterListReceiverT) 987 } 988 } 989 } 990 991 // val <T : String> T.oneTypeParameterWithBoundsReceiver 992 val oneTypeParameterWithBoundsReceiver = 993 fooClass.assertProperty("oneTypeParameterWithBoundsReceiver") 994 val oneTypeParameterWithBoundsReceiverT = 995 oneTypeParameterWithBoundsReceiver.typeParameterList.single() 996 assertThat(oneTypeParameterWithBoundsReceiverT.name()).isEqualTo("T") 997 assertThat(oneTypeParameterWithBoundsReceiverT.typeBounds().single().isString()) 998 .isTrue() 999 assertThat(oneTypeParameterWithBoundsReceiverT.isReified()).isFalse() 1000 oneTypeParameterWithBoundsReceiver.receiver.assertVariableTypeItem { 1001 assertEquals(asTypeParameter, oneTypeParameterReceiverT) 1002 } 1003 1004 // val <T1, T2> Map<T1, T2>.twoTypeParameterMapReceiver 1005 val twoTypeParameterMapReceiver = fooClass.assertProperty("twoTypeParameterMapReceiver") 1006 val twoTypeParameterMapReceiverT1 = twoTypeParameterMapReceiver.typeParameterList[0] 1007 assertThat(twoTypeParameterMapReceiverT1.name()).isEqualTo("T1") 1008 assertThat(twoTypeParameterMapReceiverT1.typeBounds()).isEmpty() 1009 assertThat(twoTypeParameterMapReceiverT1.isReified()).isFalse() 1010 val twoTypeParameterMapReceiverT2 = twoTypeParameterMapReceiver.typeParameterList[1] 1011 assertThat(twoTypeParameterMapReceiverT2.name()).isEqualTo("T2") 1012 assertThat(twoTypeParameterMapReceiverT2.typeBounds()).isEmpty() 1013 assertThat(twoTypeParameterMapReceiverT2.isReified()).isFalse() 1014 twoTypeParameterMapReceiver.receiver.assertClassTypeItem { 1015 assertEquals(qualifiedName, "java.util.Map") 1016 assertEquals(arguments.size, 2) 1017 arguments[0].assertVariableTypeItem { 1018 assertEquals(asTypeParameter, twoTypeParameterMapReceiverT1) 1019 } 1020 arguments[1].assertWildcardItem { 1021 extendsBound.assertVariableTypeItem { 1022 assertEquals(asTypeParameter, twoTypeParameterMapReceiverT2) 1023 } 1024 } 1025 } 1026 1027 // val <T1 : String, T2 : List<T1>> Map<T1, T2>.twoTypeParameterWithBoundsMapReceiver 1028 val twoTypeParameterWithBoundsMapReceiver = 1029 fooClass.assertProperty("twoTypeParameterWithBoundsMapReceiver") 1030 val twoTypeParameterWithBoundsMapReceiverT1 = 1031 twoTypeParameterWithBoundsMapReceiver.typeParameterList[0] 1032 assertThat(twoTypeParameterWithBoundsMapReceiverT1.name()).isEqualTo("T1") 1033 assertThat(twoTypeParameterWithBoundsMapReceiverT1.typeBounds().single().isString()) 1034 .isTrue() 1035 assertThat(twoTypeParameterWithBoundsMapReceiverT1.isReified()).isFalse() 1036 val twoTypeParameterWithBoundsMapReceiverT2 = 1037 twoTypeParameterWithBoundsMapReceiver.typeParameterList[1] 1038 assertThat(twoTypeParameterWithBoundsMapReceiverT2.name()).isEqualTo("T2") 1039 twoTypeParameterWithBoundsMapReceiverT2.typeBounds().single().assertClassTypeItem { 1040 assertEquals(qualifiedName, "java.util.List") 1041 arguments.single().assertWildcardItem { 1042 extendsBound.assertVariableTypeItem { 1043 assertEquals(asTypeParameter, twoTypeParameterWithBoundsMapReceiverT1) 1044 } 1045 } 1046 } 1047 assertThat(twoTypeParameterWithBoundsMapReceiverT2.isReified()).isFalse() 1048 twoTypeParameterWithBoundsMapReceiver.receiver.assertClassTypeItem { 1049 assertEquals(qualifiedName, "java.util.Map") 1050 assertEquals(arguments.size, 2) 1051 arguments[0].assertVariableTypeItem { 1052 assertEquals(asTypeParameter, twoTypeParameterWithBoundsMapReceiverT1) 1053 } 1054 arguments[1].assertWildcardItem { 1055 extendsBound.assertVariableTypeItem { 1056 assertEquals(asTypeParameter, twoTypeParameterWithBoundsMapReceiverT2) 1057 } 1058 } 1059 } 1060 } 1061 } 1062 1063 @Test Test property type parameters, property typenull1064 fun `Test property type parameters, property type`() { 1065 runCodebaseTest( 1066 kotlin( 1067 """ 1068 @file:JvmName("Foo") 1069 package test.pkg 1070 val <T> T.typeParameterExtension 1071 get() = this 1072 """ 1073 ), 1074 signature( 1075 """ 1076 // Signature format: 5.0 1077 package test.pkg { 1078 public final class Foo { 1079 method public static <T> T getTypeParameterExtension(T); 1080 property public static <T> T T.typeParameterExtension; 1081 } 1082 } 1083 """ 1084 ), 1085 signature( 1086 """ 1087 // Signature format: 5.0 1088 // - kotlin-name-type-order=yes 1089 package test.pkg { 1090 public final class Foo { 1091 method public static <T> getTypeParameterExtension(receiver: T): T; 1092 property public static <T> T.typeParameterExtension: T; 1093 } 1094 } 1095 """ 1096 ), 1097 ) { 1098 val fooClass = codebase.assertClass("test.pkg.Foo") 1099 // Verify that the type parameter list is also used for the property type 1100 val typeParameterExtension = fooClass.assertProperty("typeParameterExtension") 1101 val typeParameterExtensionT = typeParameterExtension.typeParameterList.single() 1102 assertThat(typeParameterExtensionT.name()).isEqualTo("T") 1103 assertThat(typeParameterExtensionT.typeBounds()).isEmpty() 1104 assertThat(typeParameterExtensionT.isReified()).isFalse() 1105 typeParameterExtension.type().assertVariableTypeItem { 1106 assertEquals(asTypeParameter, typeParameterExtensionT) 1107 } 1108 } 1109 } 1110 } 1111