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 com.android.tools.metalava.compatibility 20 import com.android.tools.metalava.model.text.TextCodebase 21 import com.android.tools.metalava.model.visitors.ItemVisitor 22 import com.android.tools.metalava.model.visitors.TypeVisitor 23 import java.util.LinkedHashSet 24 import java.util.function.Predicate 25 26 interface MethodItem : MemberItem { 27 /** Whether this method is a constructor */ 28 fun isConstructor(): Boolean 29 30 /** The type of this field, or null for constructors */ 31 fun returnType(): TypeItem? 32 33 /** The list of parameters */ 34 fun parameters(): List<ParameterItem> 35 36 /** Returns true if this method is a Kotlin extension method */ 37 fun isExtensionMethod(): Boolean 38 39 /** Returns the super methods that this method is overriding */ 40 fun superMethods(): List<MethodItem> 41 42 override fun type(): TypeItem? = returnType() 43 44 /** 45 * Like [internalName] but is the desc-portion of the internal signature, 46 * e.g. for the method "void create(int x, int y)" the internal name of 47 * the constructor is "create" and the desc is "(II)V" 48 */ 49 fun internalDesc(voidConstructorTypes: Boolean = false): String { 50 val sb = StringBuilder() 51 sb.append("(") 52 53 // Non-static inner classes get an implicit constructor parameter for the 54 // outer type 55 if (isConstructor() && containingClass().containingClass() != null && 56 !containingClass().modifiers.isStatic() 57 ) { 58 sb.append(containingClass().containingClass()?.toType()?.internalName() ?: "") 59 } 60 61 for (parameter in parameters()) { 62 sb.append(parameter.type().internalName()) 63 } 64 65 sb.append(")") 66 sb.append(if (voidConstructorTypes && isConstructor()) "V" else returnType()?.internalName() ?: "V") 67 return sb.toString() 68 } 69 70 fun allSuperMethods(): Sequence<MethodItem> { 71 val original = superMethods().firstOrNull() ?: return emptySequence() 72 return generateSequence(original) { item -> 73 val superMethods = item.superMethods() 74 superMethods.firstOrNull() 75 } 76 } 77 78 /** Any type parameters for the class, if any, as a source string (with fully qualified class names) */ 79 fun typeParameterList(): TypeParameterList 80 81 /** Returns the classes that are part of the type parameters of this method, if any */ 82 fun typeArgumentClasses(): List<ClassItem> = codebase.unsupported() 83 84 /** Types of exceptions that this method can throw */ 85 fun throwsTypes(): List<ClassItem> 86 87 /** Returns true if this class throws the given exception */ 88 fun throws(qualifiedName: String): Boolean { 89 for (type in throwsTypes()) { 90 if (type.extends(qualifiedName)) { 91 return true 92 } 93 } 94 95 for (type in throwsTypes()) { 96 if (type.qualifiedName() == qualifiedName) { 97 return true 98 } 99 } 100 101 return false 102 } 103 104 fun filteredThrowsTypes(predicate: Predicate<Item>): Collection<ClassItem> { 105 if (throwsTypes().isEmpty()) { 106 return emptyList() 107 } 108 return filteredThrowsTypes(predicate, LinkedHashSet()) 109 } 110 111 private fun filteredThrowsTypes( 112 predicate: Predicate<Item>, 113 classes: LinkedHashSet<ClassItem> 114 ): LinkedHashSet<ClassItem> { 115 116 for (cls in throwsTypes()) { 117 if (predicate.test(cls) || cls.isTypeParameter && !compatibility.useErasureInThrows) { 118 classes.add(cls) 119 } else { 120 // Excluded, but it may have super class throwables that are included; if so, include those 121 var curr = cls.publicSuperClass() 122 while (curr != null) { 123 if (predicate.test(curr)) { 124 classes.add(curr) 125 break 126 } 127 curr = curr.publicSuperClass() 128 } 129 } 130 } 131 return classes 132 } 133 134 /** 135 * If this method is inherited from a hidden super class, but implements a method 136 * from a public interface, this property is set. This is necessary because these 137 * methods should not be listed in signature files (at least not in compatibility mode), 138 * whereas in stub files it's necessary for them to be included (otherwise subclasses 139 * may think the method required and not yet implemented, e.g. the class must be 140 * abstract.) 141 */ 142 var inheritedMethod: Boolean 143 144 /** 145 * If this method is inherited from a super class (typically via [duplicate]) this 146 * field points to the original class it was inherited from 147 */ 148 var inheritedFrom: ClassItem? 149 150 /** 151 * Duplicates this field item. Used when we need to insert inherited fields from 152 * interfaces etc. 153 */ 154 fun duplicate(targetContainingClass: ClassItem): MethodItem 155 156 fun findPredicateSuperMethod(predicate: Predicate<Item>): MethodItem? { 157 if (isConstructor()) { 158 return null 159 } 160 161 val superMethods = superMethods() 162 for (method in superMethods) { 163 if (predicate.test(method)) { 164 return method 165 } 166 } 167 168 for (method in superMethods) { 169 val found = method.findPredicateSuperMethod(predicate) 170 if (found != null) { 171 return found 172 } 173 } 174 175 return null 176 } 177 178 override fun accept(visitor: ItemVisitor) { 179 if (visitor.skip(this)) { 180 return 181 } 182 183 visitor.visitItem(this) 184 if (isConstructor()) { 185 visitor.visitConstructor(this as ConstructorItem) 186 } else { 187 visitor.visitMethod(this) 188 } 189 190 for (parameter in parameters()) { 191 parameter.accept(visitor) 192 } 193 194 if (isConstructor()) { 195 visitor.afterVisitConstructor(this as ConstructorItem) 196 } else { 197 visitor.afterVisitMethod(this) 198 } 199 visitor.afterVisitItem(this) 200 } 201 202 override fun acceptTypes(visitor: TypeVisitor) { 203 if (visitor.skip(this)) { 204 return 205 } 206 207 if (!isConstructor()) { 208 val type = returnType() 209 if (type != null) { // always true when not a constructor 210 visitor.visitType(type, this) 211 } 212 } 213 214 for (parameter in parameters()) { 215 parameter.acceptTypes(visitor) 216 } 217 218 for (exception in throwsTypes()) { 219 exception.acceptTypes(visitor) 220 } 221 222 if (!isConstructor()) { 223 val type = returnType() 224 if (type != null) { 225 visitor.visitType(type, this) 226 } 227 } 228 } 229 230 companion object { 231 private fun compareMethods(o1: MethodItem, o2: MethodItem): Int { 232 val name1 = o1.name() 233 val name2 = o2.name() 234 if (name1 == name2) { 235 val rankDelta = o1.sortingRank - o2.sortingRank 236 if (rankDelta != 0) { 237 return rankDelta 238 } 239 240 // Compare by the rest of the signature to ensure stable output (we don't need to sort 241 // by return value or modifiers or modifiers or throws-lists since methods can't be overloaded 242 // by just those attributes 243 val p1 = o1.parameters() 244 val p2 = o2.parameters() 245 val p1n = p1.size 246 val p2n = p2.size 247 for (i in 0 until minOf(p1n, p2n)) { 248 val compareTypes = 249 p1[i].type().toTypeString() 250 .compareTo(p2[i].type().toTypeString(), ignoreCase = true) 251 if (compareTypes != 0) { 252 return compareTypes 253 } 254 // (Don't compare names; they're not part of the signatures) 255 } 256 return p1n.compareTo(p2n) 257 } 258 259 return name1.compareTo(name2) 260 } 261 262 val comparator: Comparator<MethodItem> = Comparator { o1, o2 -> compareMethods(o1, o2) } 263 val sourceOrderComparator: Comparator<MethodItem> = Comparator { o1, o2 -> 264 val delta = o1.sortingRank - o2.sortingRank 265 if (delta == 0) { 266 // Within a source file all the items will have unique sorting ranks, but since 267 // we copy methods in from hidden super classes it's possible for ranks to clash, 268 // and in that case we'll revert to a signature based comparison 269 comparator.compare(o1, o2) 270 } else { 271 delta 272 } 273 } 274 275 fun sameSignature(method: MethodItem, superMethod: MethodItem, compareRawTypes: Boolean = false): Boolean { 276 // If the return types differ, override it (e.g. parent implements clone(), 277 // subclass overrides with more specific return type) 278 if (method.returnType() != superMethod.returnType()) { 279 return false 280 } 281 282 if (method.deprecated != superMethod.deprecated && 283 (!compatibility.hideDifferenceImplicit || !method.deprecated)) { 284 return false 285 } 286 287 // Compare modifier lists; note that here we need to 288 // skip modifiers that don't apply in compat mode if set 289 if (!method.modifiers.equivalentTo(superMethod.modifiers)) { 290 return false 291 } 292 293 val parameterList1 = method.parameters() 294 val parameterList2 = superMethod.parameters() 295 296 if (parameterList1.size != parameterList2.size) { 297 return false 298 } 299 300 assert(parameterList1.size == parameterList2.size) 301 for (i in parameterList1.indices) { 302 val p1 = parameterList1[i] 303 val p2 = parameterList2[i] 304 val pt1 = p1.type() 305 val pt2 = p2.type() 306 307 if (compareRawTypes) { 308 if (pt1.toErasedTypeString() != pt2.toErasedTypeString()) { 309 return false 310 } 311 } else { 312 if (pt1 != pt2) { 313 return false 314 } 315 } 316 317 // TODO: Compare annotations to see for example whether 318 // you've refined the nullness policy; if so, that should be included 319 } 320 321 // Also compare throws lists 322 val throwsList12 = method.throwsTypes() 323 val throwsList2 = superMethod.throwsTypes() 324 325 if (throwsList12.size != throwsList2.size) { 326 return false 327 } 328 329 assert(throwsList12.size == throwsList2.size) 330 for (i in throwsList12.indices) { 331 val p1 = throwsList12[i] 332 val p2 = throwsList2[i] 333 val pt1 = p1.qualifiedName() 334 val pt2 = p2.qualifiedName() 335 if (pt1 != pt2) { // assumes throws lists are sorted! 336 return false 337 } 338 } 339 340 return true 341 } 342 } 343 344 fun formatParameters(): String? { 345 // TODO: Generalize, allow callers to control whether to include annotations, whether to erase types, 346 // whether to include names, etc 347 if (parameters().isEmpty()) { 348 return "" 349 } 350 val sb = StringBuilder() 351 for (parameter in parameters()) { 352 if (sb.isNotEmpty()) { 353 sb.append(", ") 354 } 355 sb.append(parameter.type().toTypeString()) 356 } 357 358 return sb.toString() 359 } 360 361 override fun requiresNullnessInfo(): Boolean { 362 if (isConstructor()) { 363 return false 364 } else if (returnType()?.primitive != true) { 365 return true 366 } 367 for (parameter in parameters()) { 368 if (!parameter.type().primitive) { 369 return true 370 } 371 } 372 return false 373 } 374 375 override fun hasNullnessInfo(): Boolean { 376 if (!requiresNullnessInfo()) { 377 return true 378 } 379 380 if (!isConstructor() && returnType()?.primitive != true) { 381 if (!modifiers.hasNullnessInfo()) { 382 return false 383 } 384 } 385 386 @Suppress("LoopToCallChain") // The quickfix is wrong! (covered by AnnotationStatisticsTest) 387 for (parameter in parameters()) { 388 if (!parameter.hasNullnessInfo()) { 389 return false 390 } 391 } 392 393 return true 394 } 395 396 fun isImplicitConstructor(): Boolean { 397 return isConstructor() && modifiers.isPublic() && parameters().isEmpty() 398 } 399 400 /** Finds uncaught exceptions actually thrown inside this method (as opposed to ones 401 * declared in the signature) */ 402 fun findThrownExceptions(): Set<ClassItem> = codebase.unsupported() 403 404 /** If annotation method, returns the default value as a source expression */ 405 fun defaultValue(): String = "" 406 407 fun hasDefaultValue(): Boolean { 408 return defaultValue() != "" 409 } 410 411 /** 412 * Check the declared default annotation value and return true if the defaults 413 * are the same. Only defined on two annotation methods; for all other 414 * methods the result is "true". 415 */ 416 fun hasSameValue(other: MethodItem): Boolean { 417 if (!containingClass().isAnnotationType() || !other.containingClass().isAnnotationType()) { 418 return true 419 } 420 421 return defaultValue() == other.defaultValue() 422 } 423 424 /** 425 * Returns true if this method is a signature match for the given method (e.g. can 426 * be overriding). This checks that the name and parameter lists match, but ignores 427 * differences in parameter names, return value types and throws list types. 428 */ 429 fun matches(other: MethodItem): Boolean { 430 if (this === other) return true 431 432 if (name() != other.name()) { 433 return false 434 } 435 436 val parameters1 = parameters() 437 val parameters2 = other.parameters() 438 439 if (parameters1.size != parameters2.size) { 440 return false 441 } 442 443 for (i in parameters1.indices) { 444 val parameter1 = parameters1[i] 445 val parameter2 = parameters2[i] 446 val typeString1 = parameter1.type().toString() 447 val typeString2 = parameter2.type().toString() 448 if (typeString1 == typeString2) { 449 continue 450 } 451 val type1 = parameter1.type().toErasedTypeString(this) 452 val type2 = parameter2.type().toErasedTypeString(other) 453 454 if (type1 != type2) { 455 // Workaround for signature-based codebase, where we can't always resolve generic 456 // parameters: if we see a mismatch here which looks like a failure to erase say T into 457 // java.lang.Object, don't treat that as a mismatch. (Similar common case: T[] and Object[]) 458 if (typeString1[0].isUpperCase() && typeString1.length == 1 && 459 parameter1.codebase is TextCodebase 460 ) { 461 continue 462 } 463 if (typeString2.length >= 2 && !typeString2[1].isLetterOrDigit() && 464 parameter1.codebase is TextCodebase 465 ) { 466 continue 467 } 468 return false 469 } 470 } 471 return true 472 } 473 474 /** Returns whether this method has any types in its signature that does not match the given filter */ 475 fun hasHiddenType(filterReference: Predicate<Item>): Boolean { 476 for (parameter in parameters()) { 477 val type = parameter.type() 478 if (type.hasTypeArguments()) { 479 for (argument in type.typeArgumentClasses()) { 480 if (!filterReference.test(argument)) { 481 return true 482 } 483 } 484 } 485 val clz = type.asClass() ?: continue 486 if (!filterReference.test(clz)) { 487 return true 488 } 489 } 490 491 val returnType = returnType() 492 if (returnType != null) { 493 val returnTypeClass = returnType.asClass() 494 if (returnTypeClass != null && !filterReference.test(returnTypeClass)) { 495 return true 496 } 497 if (returnType.hasTypeArguments()) { 498 for (argument in returnType.typeArgumentClasses()) { 499 if (!filterReference.test(argument)) { 500 return true 501 } 502 } 503 } 504 } 505 506 if (typeParameterList().typeParameterCount() > 0) { 507 for (argument in typeArgumentClasses()) { 508 if (!filterReference.test(argument)) { 509 return true 510 } 511 } 512 } 513 514 return false 515 } 516 517 override fun hasShowAnnotationInherited(): Boolean { 518 if (super.hasShowAnnotationInherited()) { 519 return true 520 } 521 return superMethods().any { 522 it.hasShowAnnotationInherited() 523 } 524 } 525 526 override fun hasShowForStubPurposesAnnotationInherited(): Boolean { 527 if (super.hasShowForStubPurposesAnnotationInherited()) { 528 return true 529 } 530 return superMethods().any { 531 it.hasShowForStubPurposesAnnotationInherited() 532 } 533 } 534 535 /** Whether this method is a getter/setter for an underlying Kotlin property (val/var) */ 536 fun isKotlinProperty(): Boolean = false 537 538 /** Returns true if this is a synthetic enum method */ 539 fun isEnumSyntheticMethod(): Boolean { 540 return containingClass().isEnum() && 541 (name() == "values" && parameters().isEmpty() || 542 name() == "valueOf" && parameters().size == 1 && 543 parameters()[0].type().isString()) 544 } 545 } 546