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