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