1 /* <lambda>null2 * Copyright (C) 2017 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 18 19 /** 20 * Represents a {@link https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html Class} 21 * 22 * If you need to model array dimensions or resolved type parameters, see {@link 23 * com.android.tools.metalava.model.TypeItem} instead 24 */ 25 @MetalavaApi 26 interface ClassItem : ClassContentItem, SelectableItem, TypeParameterListOwner { 27 /** 28 * The qualified name of a class. In class foo.bar.Outer.Inner, the qualified name is the whole 29 * thing. 30 */ 31 @MetalavaApi fun qualifiedName(): String 32 33 /** The simple name of a class. In class foo.bar.Outer.Inner, the simple name is "Inner" */ 34 fun simpleName(): String 35 36 /** The full name of a class. In class foo.bar.Outer.Inner, the full name is "Outer.Inner" */ 37 fun fullName(): String 38 39 /** Is this a nested class? */ 40 @MetalavaApi fun isNestedClass() = containingClass() != null 41 42 /** Is this a top level class? */ 43 fun isTopLevelClass(): Boolean = containingClass() == null 44 45 /** The origin of this class. */ 46 override val origin: ClassOrigin 47 48 /** This [ClassItem] and all of its nested classes, recursively */ 49 fun allClasses(): Sequence<ClassItem> { 50 return sequenceOf(this).plus(nestedClasses().asSequence().flatMap { it.allClasses() }) 51 } 52 53 override fun parent(): SelectableItem? = containingClass() ?: containingPackage() 54 55 override val effectivelyDeprecated: Boolean 56 get() = originallyDeprecated || containingClass()?.effectivelyDeprecated == true 57 58 /** Returns the internal name of the class, as seen in bytecode */ 59 fun internalName(): String { 60 var curr: ClassItem? = this 61 while (curr?.containingClass() != null) { 62 curr = curr.containingClass() 63 } 64 65 if (curr == null) { 66 return fullName().replace('.', '$') 67 } 68 69 return curr.containingPackage().qualifiedName().replace('.', '/') + 70 "/" + 71 fullName().replace('.', '$') 72 } 73 74 /** 75 * The super class of this class, if any. 76 * 77 * Interfaces always return `null` for this. 78 */ 79 @MetalavaApi fun superClass() = superClassType()?.asClass() 80 81 /** All super classes, if any */ 82 fun allSuperClasses(): Sequence<ClassItem> { 83 return generateSequence(superClass()) { it.superClass() } 84 } 85 86 /** 87 * The super class type of this class, if any. The difference between this and [superClass] is 88 * that the type reference can include type arguments; e.g. in "class MyList extends 89 * List<String>" the super class is java.util.List and the super class type is 90 * java.util.List<java.lang.String>. 91 */ 92 fun superClassType(): ClassTypeItem? 93 94 /** Returns true if this class extends the given class (includes self) */ 95 fun extends(qualifiedName: String): Boolean { 96 if (qualifiedName() == qualifiedName) { 97 return true 98 } 99 100 val superClass = superClass() 101 return superClass?.extends(qualifiedName) 102 ?: when { 103 isEnum() -> qualifiedName == JAVA_LANG_ENUM 104 isAnnotationType() -> qualifiedName == JAVA_LANG_ANNOTATION 105 else -> qualifiedName == JAVA_LANG_OBJECT 106 } 107 } 108 109 /** Returns true if this class implements the given interface (includes self) */ 110 fun implements(qualifiedName: String): Boolean { 111 if (qualifiedName() == qualifiedName) { 112 return true 113 } 114 115 interfaceTypes().forEach { 116 val cls = it.asClass() 117 if (cls != null && cls.implements(qualifiedName)) { 118 return true 119 } 120 } 121 122 // Might be implementing via superclass 123 if (superClass()?.implements(qualifiedName) == true) { 124 return true 125 } 126 127 return false 128 } 129 130 /** Returns true if this class extends or implements the given class or interface */ 131 fun extendsOrImplements(qualifiedName: String): Boolean = 132 extends(qualifiedName) || implements(qualifiedName) 133 134 /** Any interfaces implemented by this class */ 135 @MetalavaApi fun interfaceTypes(): List<ClassTypeItem> 136 137 /** 138 * All classes and interfaces implemented (by this class and its super classes and the 139 * interfaces themselves) 140 */ 141 fun allInterfaces(): Sequence<ClassItem> 142 143 /** 144 * Any classes nested in this class, that includes inner classes which are just non-static 145 * nested classes. 146 */ 147 fun nestedClasses(): List<ClassItem> 148 149 /** The constructors in this class */ 150 @MetalavaApi fun constructors(): List<ConstructorItem> 151 152 /** Whether this class has an implicit default constructor */ 153 fun hasImplicitDefaultConstructor(): Boolean 154 155 /** The non-constructor methods in this class */ 156 @MetalavaApi fun methods(): List<MethodItem> 157 158 /** The properties in this class */ 159 fun properties(): List<PropertyItem> 160 161 /** The fields in this class */ 162 @MetalavaApi fun fields(): List<FieldItem> 163 164 /** The members in this class: constructors, methods, fields/enum constants */ 165 fun members(): Sequence<MemberItem> { 166 return fields().asSequence().plus(constructors().asSequence()).plus(methods().asSequence()) 167 } 168 169 val classKind: ClassKind 170 171 /** Whether this class is an interface */ 172 fun isInterface() = classKind == ClassKind.INTERFACE 173 174 /** Whether this class is an annotation type */ 175 fun isAnnotationType() = classKind == ClassKind.ANNOTATION_TYPE 176 177 /** Whether this class is an enum */ 178 fun isEnum() = classKind == ClassKind.ENUM 179 180 /** Whether this class is a regular class (not an interface, not an enum, etc) */ 181 fun isClass() = classKind == ClassKind.CLASS 182 183 /** 184 * Whether this class is a File Facade class, i.e. a `*Kt` class that contains declarations 185 * which do not belong to a Kotlin class, e.g. top-level functions, properties, etc. 186 */ 187 fun isFileFacade() = false 188 189 /** The containing class, for nested classes */ 190 @MetalavaApi override fun containingClass(): ClassItem? 191 192 /** The containing package */ 193 override fun containingPackage(): PackageItem 194 195 /** Gets the type for this class */ 196 override fun type(): ClassTypeItem 197 198 override fun setType(type: TypeItem) = 199 error("Cannot call setType(TypeItem) on PackageItem: $this") 200 201 /** True if [freeze] has been called on this, false otherwise. */ 202 val frozen: Boolean 203 204 /** 205 * Freeze this [ClassItem] so it cannot be mutated. 206 * 207 * A frozen [ClassItem] cannot have new members (including nested classes) added or its 208 * modifiers mutated. 209 * 210 * Freezing a [ClassItem] will also freeze its super types. 211 */ 212 fun freeze() 213 214 override fun findCorrespondingItemIn( 215 codebase: Codebase, 216 superMethods: Boolean, 217 duplicate: Boolean, 218 ) = codebase.findClass(qualifiedName()) 219 220 /** Returns true if this class has type parameters */ 221 fun hasTypeVariables(): Boolean 222 223 fun isJavaLangObject(): Boolean { 224 return qualifiedName() == JAVA_LANG_OBJECT 225 } 226 227 // Mutation APIs: Used to "fix up" the API hierarchy to only expose visible parts of the API. 228 229 // This replaces the interface types implemented by this class 230 fun setInterfaceTypes(interfaceTypes: List<ClassTypeItem>) 231 232 /** The primary constructor for this class in Kotlin, if present. */ 233 val primaryConstructor: ConstructorItem? 234 get() = constructors().singleOrNull { it.isPrimary } 235 236 override fun baselineElementId() = qualifiedName() 237 238 override fun accept(visitor: ItemVisitor) { 239 visitor.visit(this) 240 } 241 242 override fun equalsToItem(other: Any?): Boolean { 243 if (this === other) return true 244 if (other !is ClassItem) return false 245 246 return qualifiedName() == other.qualifiedName() 247 } 248 249 override fun hashCodeForItem(): Int { 250 return qualifiedName().hashCode() 251 } 252 253 override fun toStringForItem() = "class ${qualifiedName()}" 254 255 companion object { 256 /** Looks up the retention policy for the given class */ 257 fun findRetention(cls: ClassItem): AnnotationRetention { 258 val modifiers = cls.modifiers 259 val annotation = modifiers.findAnnotation(AnnotationItem::isRetention) 260 val value = annotation?.findAttribute(ANNOTATION_ATTR_VALUE) 261 val source = value?.legacyValue?.toSource() 262 return when { 263 source == null -> AnnotationRetention.getDefault(cls) 264 source.contains("CLASS") -> AnnotationRetention.CLASS 265 source.contains("RUNTIME") -> AnnotationRetention.RUNTIME 266 source.contains("SOURCE") -> AnnotationRetention.SOURCE 267 source.contains("BINARY") -> AnnotationRetention.BINARY 268 else -> AnnotationRetention.getDefault(cls) 269 } 270 } 271 272 // Same as doclava1 (modulo the new handling when class names match) 273 val comparator: Comparator<in ClassItem> = Comparator { o1, o2 -> 274 val delta = o1.fullName().compareTo(o2.fullName()) 275 if (delta == 0) { 276 o1.qualifiedName().compareTo(o2.qualifiedName()) 277 } else { 278 delta 279 } 280 } 281 282 /** A partial ordering over [ClassItem] comparing [ClassItem.fullName]. */ 283 val fullNameComparator: Comparator<ClassItem> = Comparator.comparing { it.fullName() } 284 285 /** A total ordering over [ClassItem] comparing [ClassItem.qualifiedName]. */ 286 private val qualifiedComparator: Comparator<ClassItem> = 287 Comparator.comparing { it.qualifiedName() } 288 289 /** 290 * A total ordering over [ClassItem] comparing [ClassItem.fullName] first and then 291 * [ClassItem.qualifiedName]. 292 */ 293 val fullNameThenQualifierComparator: Comparator<ClassItem> = 294 fullNameComparator.thenComparing(qualifiedComparator) 295 296 fun classNameSorter(): Comparator<in ClassItem> = ClassItem.qualifiedComparator 297 } 298 299 fun findMethod( 300 template: MethodItem, 301 includeSuperClasses: Boolean = false, 302 includeInterfaces: Boolean = false 303 ): MethodItem? { 304 methods() 305 .asSequence() 306 .filter { it.matches(template) } 307 .forEach { 308 return it 309 } 310 311 if (includeSuperClasses) { 312 superClass()?.findMethod(template, true, includeInterfaces)?.let { 313 return it 314 } 315 } 316 317 if (includeInterfaces) { 318 for (itf in interfaceTypes()) { 319 val cls = itf.asClass() ?: continue 320 cls.findMethod(template, includeSuperClasses, true)?.let { 321 return it 322 } 323 } 324 } 325 return null 326 } 327 328 /** 329 * Finds a method matching the given method that satisfies the given predicate, considering all 330 * methods defined on this class and its super classes 331 */ 332 fun findPredicateMethodWithSuper(template: MethodItem, filter: FilterPredicate?): MethodItem? { 333 val method = findMethod(template, true, true) 334 if (method == null) { 335 return null 336 } 337 if (filter == null || filter.test(method)) { 338 return method 339 } 340 return method.findPredicateSuperMethod(filter) 341 } 342 343 fun findConstructor(template: ConstructorItem): ConstructorItem? { 344 constructors() 345 .asSequence() 346 .filter { it.matches(template) } 347 .forEach { 348 return it 349 } 350 return null 351 } 352 353 fun findField( 354 fieldName: String, 355 includeSuperClasses: Boolean = false, 356 includeInterfaces: Boolean = false 357 ): FieldItem? { 358 val field = fields().firstOrNull { it.name() == fieldName } 359 if (field != null) { 360 return field 361 } 362 363 if (includeSuperClasses) { 364 superClass()?.findField(fieldName, true, includeInterfaces)?.let { 365 return it 366 } 367 } 368 369 if (includeInterfaces) { 370 for (itf in interfaceTypes()) { 371 val cls = itf.asClass() ?: continue 372 cls.findField(fieldName, includeSuperClasses, true)?.let { 373 return it 374 } 375 } 376 } 377 return null 378 } 379 380 /** 381 * Find the [MethodItem] in this. 382 * 383 * It will look for [MethodItem]s whose [MethodItem.name] is equal to [methodName]. 384 * 385 * Out of those matching items it will select the first [MethodItem] whose parameters match the 386 * supplied parameters string. Parameters are matched against a candidate [MethodItem] as 387 * follows: 388 * * The [parameters] string is split on `,` and trimmed and then each item in the list is 389 * matched with the corresponding [ParameterItem] in `candidate.parameters()` as follows: 390 * * Everything after `<` is removed. 391 * * The result is compared to the result of calling [TypeItem.toErasedTypeString]`(candidate)` 392 * on the [ParameterItem.type]. 393 * 394 * If every parameter matches then the matched [MethodItem] is returned. If no `candidate` 395 * matches then it returns 'null`. 396 * 397 * @param methodName the name of the method or [simpleName] if looking for constructors. 398 * @param parameters the comma separated erased types of the parameters. 399 */ 400 fun findMethod(methodName: String, parameters: String) = 401 methods().firstOrNull { it.name() == methodName && parametersMatch(it, parameters) } 402 403 /** 404 * Find the [ConstructorItem] in this. 405 * 406 * Out of those matching items it will select the first [ConstructorItem] whose parameters match 407 * the supplied parameters string. Parameters are matched against a candidate [ConstructorItem] 408 * as follows: 409 * * The [parameters] string is split on `,` and trimmed and then each item in the list is 410 * matched with the corresponding [ParameterItem] in `candidate.parameters()` as follows: 411 * * Everything after `<` is removed. 412 * * The result is compared to the result of calling [TypeItem.toErasedTypeString]`(candidate)` 413 * on the [ParameterItem.type]. 414 * 415 * If every parameter matches then the matched [ConstructorItem] is returned. If no `candidate` 416 * matches then it returns 'null`. 417 * 418 * @param parameters the comma separated erased types of the parameters. 419 */ 420 fun findConstructor(parameters: String) = 421 constructors().firstOrNull { parametersMatch(it, parameters) } 422 423 /** 424 * Find the [CallableItem] in this. 425 * 426 * If [name] is [simpleName] then call [findConstructor] else call [findMethod]. 427 */ 428 fun findCallable(name: String, parameters: String) = 429 if (name == simpleName()) findConstructor(parameters) else findMethod(name, parameters) 430 431 private fun parametersMatch(callable: CallableItem, description: String): Boolean { 432 val parameterStrings = 433 description.splitToSequence(",").map(String::trim).filter(String::isNotEmpty).toList() 434 val parameters = callable.parameters() 435 if (parameters.size != parameterStrings.size) { 436 return false 437 } 438 for (i in parameters.indices) { 439 var parameterString = parameterStrings[i] 440 val index = parameterString.indexOf('<') 441 if (index != -1) { 442 parameterString = parameterString.substring(0, index) 443 } 444 val parameter = parameters[i].type().toErasedTypeString() 445 if (parameter != parameterString) { 446 return false 447 } 448 } 449 450 return true 451 } 452 453 /** Returns the corresponding source file, if any */ 454 fun sourceFile(): SourceFile? 455 456 /** If this class is an annotation type, returns the retention of this class */ 457 fun getRetention(): AnnotationRetention 458 459 /** 460 * Return superclass matching the given predicate. When a superclass doesn't match, we'll keep 461 * crawling up the tree until we find someone who matches. 462 */ 463 fun filteredSuperclass(predicate: FilterPredicate): ClassItem? { 464 val superClass = superClass() ?: return null 465 return if (predicate.test(superClass)) { 466 superClass 467 } else { 468 superClass.filteredSuperclass(predicate) 469 } 470 } 471 472 fun filteredSuperClassType(predicate: FilterPredicate): ClassTypeItem? { 473 var superClassType: ClassTypeItem? = superClassType() ?: return null 474 var prev: ClassItem? = null 475 while (superClassType != null) { 476 val superClass = superClassType.asClass() ?: return null 477 if (predicate.test(superClass)) { 478 if (prev == null || superClass == superClass()) { 479 // Direct reference; no need to map type variables 480 return superClassType 481 } 482 if (!superClassType.hasTypeArguments()) { 483 // No type variables - also no need for mapping 484 return superClassType 485 } 486 487 return superClassType.convertType(this, prev) as ClassTypeItem 488 } 489 490 prev = superClass 491 superClassType = superClass.superClassType() 492 } 493 494 return null 495 } 496 497 /** 498 * Return methods matching the given predicate. Forcibly includes local methods that override a 499 * matching method in an ancestor class. 500 */ 501 fun filteredMethods( 502 predicate: FilterPredicate, 503 includeSuperClassMethods: Boolean = false 504 ): Collection<MethodItem> { 505 val methods = LinkedHashSet<MethodItem>() 506 for (method in methods()) { 507 if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) { 508 // val duplicated = method.duplicate(this) 509 // methods.add(duplicated) 510 methods.remove(method) 511 methods.add(method) 512 } 513 } 514 if (includeSuperClassMethods) { 515 superClass()?.filteredMethods(predicate, includeSuperClassMethods)?.let { 516 methods += it 517 } 518 } 519 return methods 520 } 521 522 /** Returns the constructors that match the given predicate */ 523 fun filteredConstructors(predicate: FilterPredicate): Sequence<ConstructorItem> { 524 return constructors().asSequence().filter { predicate.test(it) } 525 } 526 527 /** 528 * Return fields matching the given predicate. Also clones fields from ancestors that would 529 * match had they been defined in this class. 530 */ 531 fun filteredFields(predicate: FilterPredicate, showUnannotated: Boolean): List<FieldItem> { 532 val fields = LinkedHashSet<FieldItem>() 533 if (showUnannotated) { 534 for (clazz in allInterfaces()) { 535 // If this class is an interface then it will be included in allInterfaces(). If it 536 // is a class then it will not be included. Either way, this class' fields will be 537 // handled below so there is no point in processing the fields here. 538 if (clazz == this) { 539 continue 540 } 541 if (!clazz.isInterface()) { 542 continue 543 } 544 for (field in clazz.fields()) { 545 if (!predicate.test(field)) { 546 val duplicated = field.duplicate(this) 547 if (predicate.test(duplicated)) { 548 fields.remove(duplicated) 549 fields.add(duplicated) 550 } 551 } 552 } 553 } 554 555 val superClass = superClass() 556 if (superClass != null && !predicate.test(superClass) && predicate.test(this)) { 557 // Include constants from hidden super classes. 558 for (field in superClass.fields()) { 559 val fieldModifiers = field.modifiers 560 if ( 561 !fieldModifiers.isStatic() || 562 !fieldModifiers.isFinal() || 563 !fieldModifiers.isPublic() 564 ) { 565 continue 566 } 567 if (!field.originallyHidden) { 568 val duplicated = field.duplicate(this) 569 if (predicate.test(duplicated)) { 570 fields.remove(duplicated) 571 fields.add(duplicated) 572 } 573 } 574 } 575 } 576 } 577 for (field in fields()) { 578 if (predicate.test(field)) { 579 fields.remove(field) 580 fields.add(field) 581 } 582 } 583 if (fields.isEmpty()) { 584 return emptyList() 585 } 586 val list = fields.toMutableList() 587 list.sortWith(FieldItem.comparator) 588 return list 589 } 590 591 fun filteredInterfaceTypes(predicate: FilterPredicate): Collection<ClassTypeItem> { 592 val interfaceTypes = 593 filteredInterfaceTypes( 594 predicate, 595 LinkedHashSet(), 596 includeSelf = false, 597 includeParents = false, 598 target = this 599 ) 600 601 return interfaceTypes 602 } 603 604 fun allInterfaceTypes(predicate: FilterPredicate): Collection<TypeItem> { 605 val interfaceTypes = 606 filteredInterfaceTypes( 607 predicate, 608 LinkedHashSet(), 609 includeSelf = false, 610 includeParents = true, 611 target = this 612 ) 613 if (interfaceTypes.isEmpty()) { 614 return interfaceTypes 615 } 616 617 return interfaceTypes 618 } 619 620 private fun filteredInterfaceTypes( 621 predicate: FilterPredicate, 622 types: LinkedHashSet<ClassTypeItem>, 623 includeSelf: Boolean, 624 includeParents: Boolean, 625 target: ClassItem 626 ): LinkedHashSet<ClassTypeItem> { 627 val superClassType = superClassType() 628 if (superClassType != null) { 629 val superClass = superClassType.asClass() 630 if (superClass != null) { 631 if (!predicate.test(superClass)) { 632 superClass.filteredInterfaceTypes( 633 predicate, 634 types, 635 true, 636 includeParents, 637 target 638 ) 639 } else if (includeSelf && superClass.isInterface()) { 640 types.add(superClassType) 641 if (includeParents) { 642 superClass.filteredInterfaceTypes( 643 predicate, 644 types, 645 true, 646 includeParents, 647 target 648 ) 649 } 650 } 651 } 652 } 653 for (type in interfaceTypes()) { 654 val cls = type.asClass() ?: continue 655 if (predicate.test(cls)) { 656 if (hasTypeVariables() && type.hasTypeArguments()) { 657 val replacementMap = target.mapTypeVariables(this) 658 if (replacementMap.isNotEmpty()) { 659 val mapped = type.convertType(replacementMap) 660 types.add(mapped) 661 continue 662 } 663 } 664 types.add(type) 665 if (includeParents) { 666 cls.filteredInterfaceTypes(predicate, types, true, includeParents, target) 667 } 668 } else { 669 cls.filteredInterfaceTypes(predicate, types, true, includeParents, target) 670 } 671 } 672 return types 673 } 674 675 /** 676 * Creates a map of type parameters of the target class to the type variables substituted for 677 * those parameters by this class. 678 * 679 * If this class is declared as `class A<X,Y> extends B<X,Y>`, and target class `B` is declared 680 * as `class B<M,N>`, this method returns the map `{M->X, N->Y}`. 681 * 682 * There could be multiple intermediate classes between this class and the target class, and in 683 * some cases we could be substituting in a concrete class, e.g. if this class is declared as 684 * `class MyClass extends Parent<String,Number>` and target class `Parent` is declared as `class 685 * Parent<M,N>` would return the map `{M->java.lang.String, N>java.lang.Number}`. 686 * 687 * The target class can be an interface. If the interface can be found through multiple paths in 688 * the class hierarchy, this method returns the mapping from the first path found in terms of 689 * declaration order. For instance, given declarations `class C<X, Y> implements I1<X>, I2<Y>`, 690 * `interface I1<T1> implements Root<T1>`, `interface I2<T2> implements Root<T2>`, and 691 * `interface Root<T>`, this method will return `{T->X}` as the mapping from `C` to `Root`, not 692 * `{T->Y}`. 693 */ 694 fun mapTypeVariables(target: ClassItem): TypeParameterBindings { 695 // Gather the supertypes to check for [target]. It is only possible for [target] to be found 696 // in the class hierarchy through this class's interfaces if [target] is an interface. 697 val candidates = 698 if (target.isInterface()) { 699 interfaceTypes() + superClassType() 700 } else { 701 listOf(superClassType()) 702 } 703 704 for (superClassType in candidates.filterNotNull()) { 705 superClassType as? ClassTypeItem ?: continue 706 // Get the class from the class type so that its type parameters can be accessed. 707 val declaringClass = superClassType.asClass() ?: continue 708 709 if (declaringClass.qualifiedName() == target.qualifiedName()) { 710 // The target has been found, return the map directly. 711 return mapTypeVariables(declaringClass, superClassType) 712 } else { 713 // This superClassType isn't target, but maybe it has target as a superclass. 714 val nextLevelMap = declaringClass.mapTypeVariables(target) 715 if (nextLevelMap.isNotEmpty()) { 716 val thisLevelMap = mapTypeVariables(declaringClass, superClassType) 717 // Link the two maps by removing intermediate type variables. 718 return nextLevelMap.mapValues { (_, value) -> 719 (value as? VariableTypeItem?)?.let { thisLevelMap[it.asTypeParameter] } 720 ?: value 721 } 722 } 723 } 724 } 725 return emptyMap() 726 } 727 728 /** 729 * Creates a map between the type parameters of [declaringClass] and the arguments of 730 * [classTypeItem]. 731 */ 732 private fun mapTypeVariables( 733 declaringClass: ClassItem, 734 classTypeItem: ClassTypeItem 735 ): TypeParameterBindings { 736 // Don't include arguments of class types, for consistency with the old psi implementation. 737 // i.e. if the mapping is from `T -> List<String>` then just use `T -> List`. 738 // TODO (b/319300404): remove this section 739 val classTypeArguments = 740 classTypeItem.arguments.map { 741 if (it is ClassTypeItem && it.arguments.isNotEmpty()) { 742 it.substitute(arguments = emptyList()) 743 } else { 744 it 745 } 746 // Although a `ClassTypeItem`'s arguments can be `WildcardTypeItem`s as well as 747 // `ReferenceTypeItem`s, a `ClassTypeItem` used in an extends or implements list 748 // cannot have a `WildcardTypeItem` as an argument so this cast is safe. See 749 // https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-Superclass 750 as ReferenceTypeItem 751 } 752 return declaringClass.typeParameterList.zip(classTypeArguments).toMap() 753 } 754 755 /** 756 * Creates a default constructor in this class. 757 * 758 * Default constructors that are added by Java have the same visibility as their class which is 759 * the default behavior of this method if no [visibility] is provided. However, this is also 760 * used to create default constructors in order for stub classes to compile and as they do not 761 * appear in the API they need to be marked as package private so this method allows the 762 * [visibility] to be explicitly specified by the caller. 763 * 764 * @param visibility the visibility of the constructor, defaults to the same as this class. 765 */ 766 fun createDefaultConstructor( 767 visibility: VisibilityLevel = modifiers.getVisibilityLevel() 768 ): ConstructorItem 769 770 fun addMethod(method: MethodItem) 771 772 /** 773 * Return true if a [ClassItem] could be subclassed, i.e. is not final or sealed and has at 774 * least one accessible constructor. 775 */ 776 fun isExtensible() = 777 !modifiers.isFinal() && 778 !modifiers.isSealed() && 779 constructors().any { it.isPublic || it.isProtected } 780 } 781