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.DocLevel 20 import com.android.tools.metalava.DocLevel.HIDDEN 21 import com.android.tools.metalava.DocLevel.PACKAGE 22 import com.android.tools.metalava.DocLevel.PRIVATE 23 import com.android.tools.metalava.DocLevel.PROTECTED 24 import com.android.tools.metalava.DocLevel.PUBLIC 25 import com.android.tools.metalava.Options 26 import com.android.tools.metalava.compatibility 27 import com.android.tools.metalava.options 28 import java.io.Writer 29 30 interface ModifierList { 31 val codebase: Codebase 32 fun annotations(): List<AnnotationItem> 33 34 fun owner(): Item 35 fun getVisibilityLevel(): VisibilityLevel 36 fun isPublic(): Boolean 37 fun isProtected(): Boolean 38 fun isPrivate(): Boolean 39 fun isStatic(): Boolean 40 fun isAbstract(): Boolean 41 fun isFinal(): Boolean 42 fun isNative(): Boolean 43 fun isSynchronized(): Boolean 44 fun isStrictFp(): Boolean 45 fun isTransient(): Boolean 46 fun isVolatile(): Boolean 47 fun isDefault(): Boolean 48 49 // Modifier in Kotlin, separate syntax (...) in Java but modeled as modifier here 50 fun isVarArg(): Boolean = false 51 52 // Kotlin 53 fun isSealed(): Boolean = false 54 fun isFunctional(): Boolean = false 55 fun isCompanion(): Boolean = false 56 fun isInfix(): Boolean = false 57 fun isConst(): Boolean = false 58 fun isSuspend(): Boolean = false 59 fun isOperator(): Boolean = false 60 fun isInline(): Boolean = false 61 fun isEmpty(): Boolean 62 63 fun isPackagePrivate() = !(isPublic() || isProtected() || isPrivate()) 64 fun isPublicOrProtected() = isPublic() || isProtected() 65 66 // Rename? It's not a full equality, it's whether an override's modifier set is significant 67 fun equivalentTo(other: ModifierList): Boolean { 68 if (isPublic() != other.isPublic()) return false 69 if (isProtected() != other.isProtected()) return false 70 if (isPrivate() != other.isPrivate()) return false 71 72 if (isStatic() != other.isStatic()) return false 73 if (isAbstract() != other.isAbstract()) return false 74 if (isFinal() != other.isFinal()) { return false } 75 if (compatibility.includeSynchronized && isSynchronized() != other.isSynchronized()) return false 76 if (isTransient() != other.isTransient()) return false 77 if (isVolatile() != other.isVolatile()) return false 78 79 // Default does not require an override to "remove" it 80 // if (isDefault() != other.isDefault()) return false 81 82 return true 83 } 84 85 /** Returns true if this modifier list contains any nullness information */ 86 fun hasNullnessInfo(): Boolean { 87 return annotations().any { it.isNonNull() || it.isNullable() } 88 } 89 90 /** Returns true if this modifier list contains any a Nullable annotation */ 91 fun isNullable(): Boolean { 92 return annotations().any { it.isNullable() } 93 } 94 95 /** 96 * Returns true if this modifier list contains any annotations explicitly passed in 97 * via [Options.showAnnotations] 98 */ 99 fun hasShowAnnotation(): Boolean { 100 if (options.showAnnotations.isEmpty()) { 101 return false 102 } 103 return annotations().any { 104 options.showAnnotations.matches(it) 105 } 106 } 107 108 /** 109 * Returns true if this modifier list contains any annotations explicitly passed in 110 * via [Options.showSingleAnnotations] 111 */ 112 fun hasShowSingleAnnotation(): Boolean { 113 114 if (options.showSingleAnnotations.isEmpty()) { 115 return false 116 } 117 return annotations().any { 118 options.showSingleAnnotations.matches(it) 119 } 120 } 121 122 /** 123 * Returns true if this modifier list contains any annotations explicitly passed in 124 * via [Options.showForStubPurposesAnnotations], and this is the only showAnnotation. 125 */ 126 fun onlyShowForStubPurposes(): Boolean { 127 if (options.showForStubPurposesAnnotations.isEmpty()) { 128 return false 129 } 130 return annotations().any { 131 options.showForStubPurposesAnnotations.matches(it) 132 } && !annotations().any { 133 options.showAnnotations.matches(it) && !options.showForStubPurposesAnnotations.matches(it) 134 } 135 } 136 137 /** 138 * Returns true if this modifier list contains any annotations explicitly passed in 139 * via [Options.hideAnnotations] or any annotations which are themselves annotated 140 * with meta-annotations explicitly passed in via [Options.hideMetaAnnotations] 141 * 142 * @see hasHideMetaAnnotations 143 */ 144 fun hasHideAnnotations(): Boolean { 145 if (options.hideAnnotations.isEmpty() && options.hideMetaAnnotations.isEmpty()) { 146 return false 147 } 148 return annotations().any { annotation -> 149 options.hideAnnotations.matches(annotation) || 150 annotation.resolve()?.hasHideMetaAnnotation() ?: false 151 } 152 } 153 154 /** 155 * Returns true if this modifier list contains any meta-annotations explicitly passed in 156 * via [Options.hideMetaAnnotations]. 157 * 158 * Hidden meta-annotations allow Metalava to handle concepts like Kotlin's [Experimental], 159 * which allows developers to create annotations that describe experimental features -- sets 160 * of distinct and potentially overlapping unstable API surfaces. Libraries may wish to exclude 161 * such sets of APIs from tracking and stub JAR generation by passing [Experimental] as a 162 * hidden meta-annotation. 163 */ 164 fun hasHideMetaAnnotations(): Boolean { 165 if (options.hideMetaAnnotations.isEmpty()) { 166 return false 167 } 168 return annotations().any { annotation -> 169 options.hideMetaAnnotations.contains(annotation.qualifiedName()) 170 } 171 } 172 173 /** Returns true if this modifier list contains the given annotation */ 174 fun isAnnotatedWith(qualifiedName: String): Boolean { 175 return findAnnotation(qualifiedName) != null 176 } 177 178 /** Returns the annotation of the given qualified name if found in this modifier list */ 179 fun findAnnotation(qualifiedName: String): AnnotationItem? { 180 val mappedName = AnnotationItem.mapName(codebase, qualifiedName) 181 return annotations().firstOrNull { 182 mappedName == it.qualifiedName() 183 } 184 } 185 186 /** Returns true if this modifier list has adequate access */ 187 fun checkLevel() = checkLevel(options.docLevel) 188 189 /** 190 * Returns true if this modifier list has access modifiers that 191 * are adequate for the given documentation level 192 */ 193 fun checkLevel(level: DocLevel): Boolean { 194 if (level == HIDDEN) { 195 return true 196 } else if (owner().isHiddenOrRemoved()) { 197 return false 198 } 199 return when (level) { 200 PUBLIC -> isPublic() 201 PROTECTED -> isPublic() || isProtected() 202 PACKAGE -> !isPrivate() 203 PRIVATE, HIDDEN -> true 204 } 205 } 206 207 /** 208 * Returns true if the visibility modifiers in this modifier list is as least as visible 209 * as the ones in the given [other] modifier list 210 */ 211 fun asAccessibleAs(other: ModifierList): Boolean { 212 val otherLevel = other.getVisibilityLevel() 213 val thisLevel = getVisibilityLevel() 214 // Generally the access level enum order determines relative visibility. However, there is an exception because 215 // package private and internal are not directly comparable. 216 val result = thisLevel >= otherLevel 217 return when (otherLevel) { 218 VisibilityLevel.PACKAGE_PRIVATE -> result && thisLevel != VisibilityLevel.INTERNAL 219 VisibilityLevel.INTERNAL -> result && thisLevel != VisibilityLevel.PACKAGE_PRIVATE 220 else -> result 221 } 222 } 223 224 /** User visible description of the visibility in this modifier list */ 225 fun getVisibilityString(): String { 226 return getVisibilityLevel().userVisibleDescription 227 } 228 229 /** 230 * Like [getVisibilityString], but package private has no modifiers; this typically corresponds to 231 * the source code for the visibility modifiers in the modifier list 232 */ 233 fun getVisibilityModifiers(): String { 234 return getVisibilityLevel().javaSourceCodeModifier 235 } 236 237 companion object { 238 fun write( 239 writer: Writer, 240 modifiers: ModifierList, 241 item: Item, 242 target: AnnotationTarget, 243 // TODO: "deprecated" isn't a modifier; clarify method name 244 includeDeprecated: Boolean = false, 245 includeAnnotations: Boolean = true, 246 runtimeAnnotationsOnly: Boolean = false, 247 skipNullnessAnnotations: Boolean = false, 248 omitCommonPackages: Boolean = false, 249 removeAbstract: Boolean = false, 250 removeFinal: Boolean = false, 251 addPublic: Boolean = false, 252 separateLines: Boolean = false, 253 language: Language = Language.JAVA 254 ) { 255 256 val list = if (removeAbstract || removeFinal || addPublic) { 257 class AbstractFiltering : ModifierList by modifiers { 258 override fun isAbstract(): Boolean { 259 return if (removeAbstract) false else modifiers.isAbstract() 260 } 261 262 override fun isFinal(): Boolean { 263 return if (removeFinal) false else modifiers.isFinal() 264 } 265 266 override fun getVisibilityLevel(): VisibilityLevel { 267 return if (addPublic) VisibilityLevel.PUBLIC else modifiers.getVisibilityLevel() 268 } 269 } 270 AbstractFiltering() 271 } else { 272 modifiers 273 } 274 275 if (includeAnnotations) { 276 writeAnnotations( 277 item, 278 target, 279 runtimeAnnotationsOnly, 280 includeDeprecated, 281 writer, 282 separateLines, 283 list, 284 skipNullnessAnnotations, 285 omitCommonPackages 286 ) 287 } else { 288 // We always include @Deprecated annotation in stub files 289 if (item.deprecated && target.isStubsFile()) { 290 writer.write("@Deprecated") 291 writer.write(if (separateLines) "\n" else " ") 292 } 293 } 294 295 if (item is PackageItem) { 296 // Packages use a modifier list, but only annotations apply 297 return 298 } 299 300 // Kotlin order: 301 // https://kotlinlang.org/docs/reference/coding-conventions.html#modifiers 302 303 // Abstract: should appear in interfaces if in compat mode 304 val classItem = item as? ClassItem 305 val methodItem = item as? MethodItem 306 307 // Order based on the old stubs code: TODO, use Java standard order instead? 308 309 if (compatibility.nonstandardModifierOrder) { 310 val visibilityLevel = list.getVisibilityLevel() 311 if (visibilityLevel != VisibilityLevel.PACKAGE_PRIVATE) { 312 writer.write(visibilityLevel.javaSourceCodeModifier + " ") 313 } 314 315 if (list.isDefault()) { 316 writer.write("default ") 317 } 318 319 if (list.isStatic() && (compatibility.staticEnums || classItem == null || !classItem.isEnum())) { 320 writer.write("static ") 321 } 322 323 if (list.isFinal() && 324 // Don't show final on parameters: that's an implementation side detail 325 item !is ParameterItem && 326 (classItem?.isEnum() != true || compatibility.finalInInterfaces) || 327 compatibility.forceFinalInEnumValueMethods && 328 methodItem?.name() == "values" && methodItem.containingClass().isEnum() 329 ) { 330 writer.write("final ") 331 } 332 333 if (list.isSealed()) { 334 writer.write("sealed ") 335 } 336 337 if (list.isSuspend()) { 338 writer.write("suspend ") 339 } 340 341 if (list.isInline()) { 342 writer.write("inline ") 343 } 344 345 if (list.isInfix()) { 346 writer.write("infix ") 347 } 348 349 if (list.isOperator()) { 350 writer.write("operator ") 351 } 352 353 val isInterface = classItem?.isInterface() == true || 354 (methodItem?.containingClass()?.isInterface() == true && 355 !list.isDefault() && !list.isStatic()) 356 357 if ((compatibility.abstractInInterfaces && isInterface || 358 list.isAbstract() && 359 (classItem?.isEnum() != true && 360 (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true))) && 361 (!isInterface || compatibility.abstractInInterfaces) 362 ) { 363 writer.write("abstract ") 364 } 365 366 if (list.isNative() && target.isStubsFile()) { 367 writer.write("native ") 368 } 369 370 if (item.deprecated && includeDeprecated && !target.isStubsFile() && !compatibility.deprecatedAsAnnotation) { 371 writer.write("deprecated ") 372 } 373 374 if (list.isSynchronized() && (compatibility.includeSynchronized || target.isStubsFile())) { 375 writer.write("synchronized ") 376 } 377 378 if (list.isTransient()) { 379 writer.write("transient ") 380 } 381 382 if (list.isVolatile()) { 383 writer.write("volatile ") 384 } 385 } else { 386 if (item.deprecated && includeDeprecated && !target.isStubsFile() && !compatibility.deprecatedAsAnnotation) { 387 writer.write("deprecated ") 388 } 389 390 val visibilityLevel = list.getVisibilityLevel() 391 val modifier = if (language == Language.JAVA) { 392 visibilityLevel.javaSourceCodeModifier 393 } else { 394 visibilityLevel.kotlinSourceCodeModifier 395 } 396 if (modifier.isNotEmpty()) { 397 writer.write("$modifier ") 398 } 399 400 val isInterface = classItem?.isInterface() == true || 401 (methodItem?.containingClass()?.isInterface() == true && 402 !list.isDefault() && !list.isStatic()) 403 404 if ((compatibility.abstractInInterfaces && isInterface || 405 list.isAbstract() && 406 (classItem?.isEnum() != true && 407 (compatibility.abstractInAnnotations || classItem?.isAnnotationType() != true))) && 408 (!isInterface || compatibility.abstractInInterfaces) 409 ) { 410 writer.write("abstract ") 411 } 412 413 if (list.isDefault() && item !is ParameterItem) { 414 writer.write("default ") 415 } 416 417 if (list.isStatic() && (compatibility.staticEnums || classItem == null || !classItem.isEnum())) { 418 writer.write("static ") 419 } 420 421 if (list.isFinal() && 422 language == Language.JAVA && 423 // Don't show final on parameters: that's an implementation side detail 424 item !is ParameterItem && 425 (classItem?.isEnum() != true || compatibility.finalInInterfaces) 426 ) { 427 writer.write("final ") 428 } else if (!list.isFinal() && language == Language.KOTLIN) { 429 writer.write("open ") 430 } 431 432 if (list.isSealed()) { 433 writer.write("sealed ") 434 } 435 436 if (list.isSuspend()) { 437 writer.write("suspend ") 438 } 439 440 if (list.isInline()) { 441 writer.write("inline ") 442 } 443 444 if (list.isInfix()) { 445 writer.write("infix ") 446 } 447 448 if (list.isOperator()) { 449 writer.write("operator ") 450 } 451 452 if (list.isTransient()) { 453 writer.write("transient ") 454 } 455 456 if (list.isVolatile()) { 457 writer.write("volatile ") 458 } 459 460 if (list.isSynchronized() && (compatibility.includeSynchronized || target.isStubsFile())) { 461 writer.write("synchronized ") 462 } 463 464 if (list.isNative() && target.isStubsFile()) { 465 writer.write("native ") 466 } 467 468 if (list.isFunctional()) { 469 writer.write("fun ") 470 } 471 } 472 } 473 474 fun writeAnnotations( 475 item: Item, 476 target: AnnotationTarget, 477 runtimeAnnotationsOnly: Boolean, 478 includeDeprecated: Boolean, 479 writer: Writer, 480 separateLines: Boolean, 481 list: ModifierList, 482 skipNullnessAnnotations: Boolean, 483 omitCommonPackages: Boolean 484 ) { 485 // if includeDeprecated we want to do it 486 // unless runtimeOnly is false, in which case we'd include it too 487 // e.g. emit @Deprecated if includeDeprecated && !runtimeOnly 488 if (item.deprecated && 489 (compatibility.deprecatedAsAnnotation || target.isStubsFile()) && 490 (runtimeAnnotationsOnly || includeDeprecated) 491 ) { 492 writer.write("@Deprecated") 493 writer.write(if (separateLines) "\n" else " ") 494 } 495 496 writeAnnotations( 497 list = list, 498 runtimeAnnotationsOnly = runtimeAnnotationsOnly, 499 skipNullnessAnnotations = skipNullnessAnnotations, 500 omitCommonPackages = omitCommonPackages, 501 separateLines = separateLines, 502 writer = writer, 503 target = target 504 ) 505 } 506 507 fun writeAnnotations( 508 list: ModifierList, 509 skipNullnessAnnotations: Boolean = false, 510 runtimeAnnotationsOnly: Boolean = false, 511 omitCommonPackages: Boolean = false, 512 separateLines: Boolean = false, 513 filterDuplicates: Boolean = false, 514 writer: Writer, 515 target: AnnotationTarget 516 ) { 517 var annotations = list.annotations() 518 519 // Ensure stable signature file order 520 if (annotations.size > 1) { 521 annotations = annotations.sortedBy { it.qualifiedName() } 522 } 523 524 if (annotations.isNotEmpty()) { 525 var index = -1 526 for (annotation in annotations) { 527 index++ 528 529 if (runtimeAnnotationsOnly && annotation.retention != AnnotationRetention.RUNTIME) { 530 continue 531 } 532 533 var printAnnotation = annotation 534 if (!annotation.targets().contains(target)) { 535 continue 536 } else if ((annotation.isNullnessAnnotation())) { 537 if (skipNullnessAnnotations) { 538 continue 539 } 540 } else if (annotation.qualifiedName() == "java.lang.Deprecated") { 541 // Special cased in stubs and signature files: emitted first 542 continue 543 } else if (options.typedefMode == Options.TypedefMode.INLINE) { 544 val typedef = annotation.findTypedefAnnotation() 545 if (typedef != null) { 546 printAnnotation = typedef 547 } 548 } else if (options.typedefMode == Options.TypedefMode.REFERENCE && 549 annotation.targets() === ANNOTATION_SIGNATURE_ONLY && 550 annotation.findTypedefAnnotation() != null) { 551 // For annotation references, only include the simple name 552 writer.write("@") 553 writer.write(annotation.resolve()?.simpleName() ?: annotation.qualifiedName()!!) 554 if (separateLines) { 555 writer.write("\n") 556 } else { 557 writer.write(" ") 558 } 559 continue 560 } 561 562 // Optionally filter out duplicates 563 if (index > 0 && filterDuplicates) { 564 val qualifiedName = annotation.qualifiedName() 565 var found = false 566 for (i in 0 until index) { 567 val prev = annotations[i] 568 if (prev.qualifiedName() == qualifiedName) { 569 found = true 570 break 571 } 572 } 573 if (found) { 574 continue 575 } 576 } 577 578 val source = printAnnotation.toSource(target, showDefaultAttrs = false) 579 580 if (omitCommonPackages) { 581 writer.write(AnnotationItem.shortenAnnotation(source)) 582 } else { 583 writer.write(source) 584 } 585 if (separateLines) { 586 writer.write("\n") 587 } else { 588 writer.write(" ") 589 } 590 } 591 } 592 } 593 } 594 } 595