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.psi 18 19 import com.android.tools.metalava.model.ANDROID_DEPRECATED_FOR_SDK 20 import com.android.tools.metalava.model.AnnotationItem 21 import com.android.tools.metalava.model.BaseModifierList 22 import com.android.tools.metalava.model.JAVA_LANG_ANNOTATION_TARGET 23 import com.android.tools.metalava.model.JAVA_LANG_TYPE_USE_TARGET 24 import com.android.tools.metalava.model.JVM_STATIC 25 import com.android.tools.metalava.model.ModifierFlags.Companion.ABSTRACT 26 import com.android.tools.metalava.model.ModifierFlags.Companion.ACTUAL 27 import com.android.tools.metalava.model.ModifierFlags.Companion.COMPANION 28 import com.android.tools.metalava.model.ModifierFlags.Companion.CONST 29 import com.android.tools.metalava.model.ModifierFlags.Companion.DATA 30 import com.android.tools.metalava.model.ModifierFlags.Companion.DEFAULT 31 import com.android.tools.metalava.model.ModifierFlags.Companion.EXPECT 32 import com.android.tools.metalava.model.ModifierFlags.Companion.FINAL 33 import com.android.tools.metalava.model.ModifierFlags.Companion.FUN 34 import com.android.tools.metalava.model.ModifierFlags.Companion.INFIX 35 import com.android.tools.metalava.model.ModifierFlags.Companion.INLINE 36 import com.android.tools.metalava.model.ModifierFlags.Companion.INTERNAL 37 import com.android.tools.metalava.model.ModifierFlags.Companion.NATIVE 38 import com.android.tools.metalava.model.ModifierFlags.Companion.OPERATOR 39 import com.android.tools.metalava.model.ModifierFlags.Companion.PACKAGE_PRIVATE 40 import com.android.tools.metalava.model.ModifierFlags.Companion.PRIVATE 41 import com.android.tools.metalava.model.ModifierFlags.Companion.PROTECTED 42 import com.android.tools.metalava.model.ModifierFlags.Companion.PUBLIC 43 import com.android.tools.metalava.model.ModifierFlags.Companion.SEALED 44 import com.android.tools.metalava.model.ModifierFlags.Companion.STATIC 45 import com.android.tools.metalava.model.ModifierFlags.Companion.STRICT_FP 46 import com.android.tools.metalava.model.ModifierFlags.Companion.SUSPEND 47 import com.android.tools.metalava.model.ModifierFlags.Companion.SYNCHRONIZED 48 import com.android.tools.metalava.model.ModifierFlags.Companion.TRANSIENT 49 import com.android.tools.metalava.model.ModifierFlags.Companion.VALUE 50 import com.android.tools.metalava.model.ModifierFlags.Companion.VARARG 51 import com.android.tools.metalava.model.ModifierFlags.Companion.VOLATILE 52 import com.android.tools.metalava.model.MutableModifierList 53 import com.android.tools.metalava.model.VisibilityLevel 54 import com.android.tools.metalava.model.createMutableModifiers 55 import com.android.tools.metalava.model.hasAnnotation 56 import com.android.tools.metalava.model.isNullnessAnnotation 57 import com.intellij.psi.PsiAnnotation 58 import com.intellij.psi.PsiAnnotationMemberValue 59 import com.intellij.psi.PsiArrayInitializerMemberValue 60 import com.intellij.psi.PsiElement 61 import com.intellij.psi.PsiField 62 import com.intellij.psi.PsiMethod 63 import com.intellij.psi.PsiModifier 64 import com.intellij.psi.PsiModifierList 65 import com.intellij.psi.PsiModifierListOwner 66 import com.intellij.psi.PsiParameter 67 import com.intellij.psi.PsiPrimitiveType 68 import com.intellij.psi.PsiReferenceExpression 69 import com.intellij.psi.impl.light.LightModifierList 70 import org.jetbrains.annotations.NotNull 71 import org.jetbrains.annotations.Nullable 72 import org.jetbrains.kotlin.analysis.api.analyze 73 import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolVisibility 74 import org.jetbrains.kotlin.asJava.elements.KtLightElement 75 import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget 76 import org.jetbrains.kotlin.lexer.KtModifierKeywordToken 77 import org.jetbrains.kotlin.lexer.KtTokens 78 import org.jetbrains.kotlin.psi.KtAnnotated 79 import org.jetbrains.kotlin.psi.KtClass 80 import org.jetbrains.kotlin.psi.KtConstructor 81 import org.jetbrains.kotlin.psi.KtDeclaration 82 import org.jetbrains.kotlin.psi.KtElement 83 import org.jetbrains.kotlin.psi.KtFunction 84 import org.jetbrains.kotlin.psi.KtModifierList 85 import org.jetbrains.kotlin.psi.KtModifierListOwner 86 import org.jetbrains.kotlin.psi.KtNamedFunction 87 import org.jetbrains.kotlin.psi.KtProperty 88 import org.jetbrains.kotlin.psi.KtPropertyAccessor 89 import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject 90 import org.jetbrains.kotlin.psi.psiUtil.isTopLevelKtOrJavaMember 91 import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier 92 import org.jetbrains.uast.UAnnotated 93 import org.jetbrains.uast.UAnnotation 94 import org.jetbrains.uast.UElement 95 import org.jetbrains.uast.UMethod 96 import org.jetbrains.uast.UVariable 97 import org.jetbrains.uast.kotlin.KotlinUMethodWithFakeLightDelegateBase 98 import org.jetbrains.uast.toUElement 99 100 internal object PsiModifierItem { 101 fun create( 102 codebase: PsiBasedCodebase, 103 element: PsiModifierListOwner, 104 ): MutableModifierList { 105 val modifiers = 106 if (element is UAnnotated) { 107 createFromUAnnotated(codebase, element, element) 108 } else { 109 createFromPsiElement(codebase, element) 110 } 111 112 // Sometimes Psi/Kotlin interoperation goes a little awry and adds nullability annotations 113 // that it should not, so this removes them. 114 if (shouldRemoveNullnessAnnotations(modifiers)) { 115 modifiers.mutateAnnotations { removeIf { it.isNullnessAnnotation() } } 116 } 117 118 if ( 119 hasDeprecatedAnnotation(modifiers) || 120 // Check for @Deprecated on sourcePsi 121 isDeprecatedFromSourcePsi(element) 122 ) { 123 modifiers.setDeprecated(true) 124 } 125 126 return modifiers 127 } 128 129 /** 130 * Creates modifiers for the property represented by [ktDeclaration] using the [KtModifierList] 131 * and from the property. Uses annotations from the [getter] if it exists in addition to 132 * property annotations because property modifiers used to be created just from the getter and 133 * some places rely on the old behavior for annotations (@RestrictTo in AndroidX is only 134 * applicable to accessors, not properties themselves). 135 */ 136 fun createForProperty( 137 codebase: PsiBasedCodebase, 138 ktDeclaration: KtDeclaration, 139 getter: PsiMethodItem?, 140 setter: PsiMethodItem?, 141 ): MutableModifierList { 142 val ktModifierList = ktDeclaration.modifierList 143 val visibilityFlags = 144 visibilityFlags( 145 psiModifierList = null, 146 ktModifierList = ktModifierList, 147 element = ktDeclaration, 148 sourcePsi = ktDeclaration 149 ) 150 val kotlinFlags = kotlinFlags { token -> 151 ktModifierList?.hasModifier(token) ?: ktDeclaration.hasModifier(token) 152 } 153 val javaFlags = javaFlagsForKotlinElement(ktDeclaration) 154 val flags = visibilityFlags or kotlinFlags or javaFlags 155 156 // Use the flags computed from the property, and the getter annotations, if they exist. 157 val modifiers = 158 createMutableModifiers( 159 flags, 160 // Filter deprecated annotations: the property will pull effectivelyDeprecated 161 // status from its getter, but the originallyDeprecated value should reflect 162 // the property itself, to avoid propagating deprecation from getter to property to 163 // setter. The setter should only inherit deprecation from the property itself. 164 getter?.modifiers?.annotations()?.filter { !isDeprecatedAnnotation(it) } 165 ?: emptyList() 166 ) 167 168 // Correct visibility of accessors (work around K2 bugs with value class type properties) 169 // https://youtrack.jetbrains.com/issue/KT-74205 170 // The getter must have the same visibility as the property 171 val propertyVisibility = modifiers.getVisibilityLevel() 172 if (getter != null && getter.modifiers.getVisibilityLevel() != propertyVisibility) { 173 getter.mutateModifiers { setVisibilityLevel(modifiers.getVisibilityLevel()) } 174 } 175 // The setter cannot be more visible than the property 176 if (setter != null && setter.modifiers.getVisibilityLevel() > propertyVisibility) { 177 setter.mutateModifiers { setVisibilityLevel(modifiers.getVisibilityLevel()) } 178 } 179 180 // Annotations whose target is property won't be bound to anywhere in LC/UAST, if the 181 // property doesn't need a backing field. Same for unspecified use-site target. 182 // Add all annotations applied to the property by examining source PSI directly. 183 for (ktAnnotationEntry in ktDeclaration.annotationEntries) { 184 val useSiteTarget = ktAnnotationEntry.useSiteTarget?.getAnnotationUseSiteTarget() 185 if (useSiteTarget == null || useSiteTarget == AnnotationUseSiteTarget.PROPERTY) { 186 val uAnnotation = ktAnnotationEntry.toUElement() as? UAnnotation ?: continue 187 val annotationItem = UAnnotationItem.create(codebase, uAnnotation) ?: continue 188 if (annotationItem !in modifiers.annotations()) { 189 modifiers.addAnnotation(annotationItem) 190 } 191 // Make sure static definitions are marked 192 if (annotationItem.qualifiedName == JVM_STATIC) { 193 modifiers.setStatic(true) 194 } 195 } 196 } 197 198 if (hasDeprecatedAnnotation(modifiers)) { 199 modifiers.setDeprecated(true) 200 } 201 202 return modifiers 203 } 204 205 /** 206 * Creates modifiers for a [ktDeclaration] that does not have an equivalent psi element which 207 * can be used with [create]. If the [ktDeclaration] is a property, [createForProperty] should 208 * be used instead. 209 */ 210 fun createForKtDeclaration( 211 codebase: PsiBasedCodebase, 212 ktDeclaration: KtDeclaration 213 ): MutableModifierList { 214 val ktModifierList = ktDeclaration.modifierList 215 val visibilityFlags = 216 visibilityFlags( 217 psiModifierList = null, 218 ktModifierList = ktModifierList, 219 element = ktDeclaration, 220 sourcePsi = ktDeclaration 221 ) 222 val kotlinFlags = kotlinFlags { token -> 223 ktModifierList?.hasModifier(token) ?: ktDeclaration.hasModifier(token) 224 } 225 val flags = visibilityFlags or kotlinFlags 226 227 val annotations = 228 ktDeclaration.annotationEntries.mapNotNull { ktAnnotationEntry -> 229 (ktAnnotationEntry.toUElement() as? UAnnotation)?.let { uAnnotation -> 230 UAnnotationItem.create(codebase, uAnnotation) 231 } 232 } 233 234 val modifiers = 235 createMutableModifiers( 236 flags, 237 annotations, 238 ) 239 240 if (hasDeprecatedAnnotation(modifiers)) { 241 modifiers.setDeprecated(true) 242 } 243 244 return modifiers 245 } 246 247 /** Determine whether nullness annotations need removing from [modifiers]. */ 248 private fun shouldRemoveNullnessAnnotations( 249 modifiers: BaseModifierList, 250 ): Boolean { 251 // Kotlin varargs are not nullable but can sometimes and up with an @Nullable annotation 252 // added to the [PsiParameter] so remove it from the modifiers. Only Kotlin varargs have a 253 // `vararg` modifier. 254 if (modifiers.isVarArg()) { 255 return true 256 } 257 258 return false 259 } 260 261 private fun hasDeprecatedAnnotation(modifiers: BaseModifierList) = 262 modifiers.hasAnnotation(::isDeprecatedAnnotation) 263 264 private fun isDeprecatedAnnotation(annotationItem: AnnotationItem): Boolean = 265 annotationItem.qualifiedName.let { qualifiedName -> 266 qualifiedName == "Deprecated" || 267 qualifiedName.endsWith(".Deprecated") || 268 // DeprecatedForSdk that do not apply to this API surface have been filtered 269 // out so if any are left then treat it as a standard Deprecated annotation. 270 qualifiedName == ANDROID_DEPRECATED_FOR_SDK 271 } 272 273 private fun isDeprecatedFromSourcePsi(element: PsiModifierListOwner): Boolean { 274 if (element is UMethod) { 275 // NB: we can't use sourcePsi.annotationEntries directly due to 276 // annotation use-site targets. The given `javaPsi` as a light element, 277 // which spans regular functions, property accessors, etc., is already 278 // built with targeted annotations. Even KotlinUMethod is using LC annotations. 279 return element.javaPsi.isDeprecated 280 } 281 return ((element as? UElement)?.sourcePsi as? KtAnnotated)?.annotationEntries?.any { 282 it.shortName?.toString() == "Deprecated" 283 } 284 ?: false 285 } 286 287 private fun computeFlag(element: PsiModifierListOwner, modifierList: PsiModifierList): Int { 288 // Look for a KtModifierList to compute visibility and Kotlin-specific modifiers. 289 var ktModifierList: KtModifierList? = null 290 val sourcePsi = (element as? UElement)?.sourcePsi 291 when (modifierList) { 292 is KtLightElement<*, *> -> { 293 ktModifierList = modifierList.kotlinOrigin as? KtModifierList 294 } 295 is LightModifierList -> { 296 if (sourcePsi is KtModifierListOwner) { 297 ktModifierList = sourcePsi.modifierList 298 } 299 } 300 } 301 302 // Compute flags that exist in java. 303 var flags = 304 if ( 305 element is KotlinUMethodWithFakeLightDelegateBase<*> && sourcePsi is KtDeclaration 306 ) { 307 // Fake elements from kotlin (e.g. methods that use value class types) may not have 308 // the correct modifiers (https://youtrack.jetbrains.com/issue/KTIJ-33047). Compute 309 // them directly from the source instead. 310 // Use the property element directly for accessors because some values aren't 311 // defined for accessors (e.g. containingClassOrObject is null). 312 javaFlagsForKotlinElement((sourcePsi as? KtPropertyAccessor)?.property ?: sourcePsi) 313 } else { 314 javaFlags(modifierList) 315 } 316 317 // Merge in the visibility flags. 318 val visibilityFlags = visibilityFlags(modifierList, ktModifierList, element, sourcePsi) 319 flags = flags or visibilityFlags 320 321 // Merge in kotlin flags 322 if (ktModifierList != null) { 323 flags = flags or kotlinFlags { token -> ktModifierList.hasModifier(token) } 324 } 325 return flags 326 } 327 328 /** Determine the element visibility, which can come from several sources. */ 329 private fun visibilityFlags( 330 psiModifierList: PsiModifierList?, 331 ktModifierList: KtModifierList?, 332 element: PsiElement?, 333 sourcePsi: PsiElement? 334 ): Int { 335 var visibilityFlags = 336 when { 337 psiModifierList?.hasModifierProperty(PsiModifier.PUBLIC) == true -> PUBLIC 338 psiModifierList?.hasModifierProperty(PsiModifier.PROTECTED) == true -> PROTECTED 339 psiModifierList?.hasModifierProperty(PsiModifier.PRIVATE) == true -> PRIVATE 340 ktModifierList != null -> 341 when { 342 ktModifierList.hasModifier(KtTokens.PRIVATE_KEYWORD) -> PRIVATE 343 ktModifierList.hasModifier(KtTokens.PROTECTED_KEYWORD) -> PROTECTED 344 ktModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD) -> INTERNAL 345 else -> PUBLIC 346 } 347 // UAST workaround: fake light method for inline/hidden function may not have a 348 // concrete modifier list, but overrides `hasModifierProperty` to mimic 349 // modifiers. 350 element is KotlinUMethodWithFakeLightDelegateBase<*> -> 351 when { 352 element.hasModifierProperty(PsiModifier.PUBLIC) -> PUBLIC 353 element.hasModifierProperty(PsiModifier.PROTECTED) -> PROTECTED 354 element.hasModifierProperty(PsiModifier.PRIVATE) -> PRIVATE 355 else -> PUBLIC 356 } 357 sourcePsi is KtModifierListOwner -> 358 when { 359 sourcePsi.hasModifier(KtTokens.PRIVATE_KEYWORD) -> PRIVATE 360 sourcePsi.hasModifier(KtTokens.PROTECTED_KEYWORD) -> PROTECTED 361 sourcePsi.hasModifier(KtTokens.INTERNAL_KEYWORD) -> INTERNAL 362 else -> PUBLIC 363 } 364 else -> PACKAGE_PRIVATE 365 } 366 if (ktModifierList != null) { 367 if (ktModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD)) { 368 // Reset visibilityFlags to INTERNAL if the internal modifier is explicitly 369 // present on the element 370 visibilityFlags = INTERNAL 371 } else if ( 372 ktModifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD) && 373 ktModifierList.visibilityModifier() == null && 374 sourcePsi is KtElement 375 ) { 376 // Reset visibilityFlags to INTERNAL if the element has no explicit visibility 377 // modifier, but overrides an internal declaration. Adapted from 378 // org.jetbrains.kotlin.asJava.classes.UltraLightMembersCreator.isInternal 379 analyze(sourcePsi) { 380 val symbol = (sourcePsi as? KtDeclaration)?.symbol 381 val visibility = symbol?.visibility 382 if (visibility == KaSymbolVisibility.INTERNAL) { 383 visibilityFlags = INTERNAL 384 } 385 } 386 } 387 } 388 389 if (ktModifierList?.hasModifier(KtTokens.INLINE_KEYWORD) == true) { 390 // Workaround for b/117565118: 391 val func = sourcePsi as? KtNamedFunction 392 if ( 393 func != null && 394 (func.typeParameterList?.text ?: "").contains(KtTokens.REIFIED_KEYWORD.value) && 395 !ktModifierList.hasModifier(KtTokens.PRIVATE_KEYWORD) && 396 !ktModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD) 397 ) { 398 // Switch back from private to public 399 visibilityFlags = PUBLIC 400 } 401 } 402 403 // Methods that are property accessors inherit visibility from the source element 404 if (element is UMethod && (element.sourceElement is KtPropertyAccessor)) { 405 val sourceElement = element.sourceElement 406 if (sourceElement is KtModifierListOwner) { 407 val sourceModifierList = sourceElement.modifierList 408 if (sourceModifierList != null) { 409 if (sourceModifierList.hasModifier(KtTokens.INTERNAL_KEYWORD)) { 410 visibilityFlags = INTERNAL 411 } 412 } 413 } 414 } 415 416 return visibilityFlags 417 } 418 419 /** 420 * Computes flags that exist in Java, excluding visibility flags. These are for both Java and 421 * Kotlin source elements. 422 */ 423 private fun javaFlags(modifierList: PsiModifierList): Int { 424 var flags = 0 425 if (modifierList.hasModifierProperty(PsiModifier.STATIC)) { 426 flags = flags or STATIC 427 } 428 if (modifierList.hasModifierProperty(PsiModifier.ABSTRACT)) { 429 flags = flags or ABSTRACT 430 } 431 if (modifierList.hasModifierProperty(PsiModifier.FINAL)) { 432 flags = flags or FINAL 433 } 434 if (modifierList.hasModifierProperty(PsiModifier.NATIVE)) { 435 flags = flags or NATIVE 436 } 437 if (modifierList.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { 438 flags = flags or SYNCHRONIZED 439 } 440 if (modifierList.hasModifierProperty(PsiModifier.STRICTFP)) { 441 flags = flags or STRICT_FP 442 } 443 if (modifierList.hasModifierProperty(PsiModifier.TRANSIENT)) { 444 flags = flags or TRANSIENT 445 } 446 if (modifierList.hasModifierProperty(PsiModifier.VOLATILE)) { 447 flags = flags or VOLATILE 448 } 449 if (modifierList.hasModifierProperty(PsiModifier.DEFAULT)) { 450 flags = flags or DEFAULT 451 } 452 return flags 453 } 454 455 /** Computes Kotlin-specific flags. */ 456 private fun kotlinFlags(hasModifier: (KtModifierKeywordToken) -> Boolean): Int { 457 var flags = 0 458 if (hasModifier(KtTokens.VARARG_KEYWORD)) { 459 flags = flags or VARARG 460 } 461 if (hasModifier(KtTokens.SEALED_KEYWORD)) { 462 flags = flags or SEALED 463 } 464 if (hasModifier(KtTokens.INFIX_KEYWORD)) { 465 flags = flags or INFIX 466 } 467 if (hasModifier(KtTokens.CONST_KEYWORD)) { 468 flags = flags or CONST 469 } 470 if (hasModifier(KtTokens.OPERATOR_KEYWORD)) { 471 flags = flags or OPERATOR 472 } 473 if (hasModifier(KtTokens.INLINE_KEYWORD)) { 474 flags = flags or INLINE 475 } 476 if (hasModifier(KtTokens.VALUE_KEYWORD)) { 477 flags = flags or VALUE 478 } 479 if (hasModifier(KtTokens.SUSPEND_KEYWORD)) { 480 flags = flags or SUSPEND 481 } 482 if (hasModifier(KtTokens.COMPANION_KEYWORD)) { 483 flags = flags or COMPANION 484 } 485 if (hasModifier(KtTokens.FUN_KEYWORD)) { 486 flags = flags or FUN 487 } 488 if (hasModifier(KtTokens.DATA_KEYWORD)) { 489 flags = flags or DATA 490 } 491 if (hasModifier(KtTokens.EXPECT_KEYWORD)) { 492 flags = flags or EXPECT 493 } 494 if (hasModifier(KtTokens.ACTUAL_KEYWORD)) { 495 flags = flags or ACTUAL 496 } 497 return flags 498 } 499 500 /** Creates Java-equivalent flags for the Kotlin element. */ 501 private fun javaFlagsForKotlinElement(ktDeclaration: KtDeclaration): Int { 502 return if ( 503 // const values are static, and anything in a file-facade class (which top level 504 // [KtDeclaration]s are) is also static 505 ktDeclaration.hasModifier(KtTokens.CONST_KEYWORD) || 506 ktDeclaration.isTopLevelKtOrJavaMember() 507 ) { 508 FINAL or STATIC 509 } else if (ktDeclaration.isAbstract()) { 510 ABSTRACT 511 } else if (ktDeclaration.isDefault()) { 512 DEFAULT 513 } else if (ktDeclaration.isFinal()) { 514 FINAL 515 } else { 516 0 517 } 518 } 519 520 private fun KtDeclaration.isFromInterface(): Boolean { 521 // Can't use containingClass() here -- don't count definitions in interface companions 522 return (containingClassOrObject as? KtClass)?.isInterface() == true 523 } 524 525 /** 526 * Checks if the [KtDeclaration] needs the abstract modifier: 527 * - if the definition used the abstract modifier 528 * - if the definition is an annotation property 529 * - if the definition is an interface property without a defined getter 530 * - if the definition is an interface function without a body 531 */ 532 private fun KtDeclaration.isAbstract(): Boolean { 533 return hasModifier(KtTokens.ABSTRACT_KEYWORD) || 534 (containingClassOrObject as? KtClass)?.isAnnotation() == true || 535 (this is KtProperty && isFromInterface() && getter?.hasBody() != true) || 536 (this is KtFunction && isFromInterface() && !hasBody()) 537 } 538 539 /** 540 * Checks if the [KtDeclaration] needs the default modifier: 541 * - if the definition is an interface property with a defined getter (interface properties 542 * cannot have backing fields, so this is the only way they can have a default implementation) 543 * - if the definition is an interface function with a body 544 */ 545 private fun KtDeclaration.isDefault(): Boolean { 546 return isFromInterface() && 547 ((this is KtProperty && getter?.hasBody() == true) || (this is KtFunction && hasBody())) 548 } 549 550 /** 551 * Checks if the [KtDeclaration] needs the final modifier. This should only be called if the 552 * definition does not need the abstract or default modifiers. 553 * - if the definition uses the final keyword 554 * - if the definition does not use the open keyword and does not use the override keyword 555 * - the definition is not a constructor -- the final modifier isn't needed for constructors as 556 * constructors can never be overridden 557 */ 558 private fun KtDeclaration.isFinal(): Boolean { 559 return hasModifier(KtTokens.FINAL_KEYWORD) || 560 (!hasModifier(KtTokens.OPEN_KEYWORD) && 561 !hasModifier(KtTokens.OVERRIDE_KEYWORD) && 562 this !is KtConstructor<*>) 563 } 564 565 /** 566 * Returns a list of the targets this annotation is defined to apply to, as qualified names 567 * (e.g. "java.lang.annotation.ElementType.TYPE_USE"). 568 * 569 * If the annotation can't be resolved or does not use `@Target`, returns an empty list. 570 */ 571 private fun PsiAnnotation.targets(): List<String> { 572 return resolveAnnotationType() 573 ?.annotations 574 ?.firstOrNull { it.hasQualifiedName(JAVA_LANG_ANNOTATION_TARGET) } 575 ?.findAttributeValue("value") 576 ?.targets() 577 ?: emptyList() 578 } 579 580 /** 581 * Returns the element types listed in the annotation value, if the value is a direct reference 582 * or an array of direct references. 583 */ 584 private fun PsiAnnotationMemberValue.targets(): List<String> { 585 return when (this) { 586 is PsiReferenceExpression -> listOf(qualifiedName) 587 is PsiArrayInitializerMemberValue -> 588 initializers.mapNotNull { (it as? PsiReferenceExpression)?.qualifiedName } 589 else -> emptyList() 590 } 591 } 592 593 /** 594 * Annotations which are only `TYPE_USE` should only apply to types, not the owning item of the 595 * type. However, psi incorrectly applies these items to both their types and owning items. 596 * 597 * If an annotation targets both `TYPE_USE` and other use sites, it should be applied to both 598 * types and owning items of the type if the owning item is one of the targeted use sites. See 599 * https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.7.4 for more detail. 600 * 601 * To work around psi incorrectly applying exclusively `TYPE_USE` annotations to non-type items, 602 * this filters all annotations which should apply to types but not the [forOwner] item. 603 */ 604 private fun List<PsiAnnotation>.filterIncorrectTypeUseAnnotations( 605 forOwner: PsiModifierListOwner 606 ): List<PsiAnnotation> { 607 val expectedTarget = 608 when (forOwner) { 609 is PsiMethod -> "java.lang.annotation.ElementType.METHOD" 610 is PsiParameter -> "java.lang.annotation.ElementType.PARAMETER" 611 is PsiField -> "java.lang.annotation.ElementType.FIELD" 612 else -> return this 613 } 614 615 return filter { annotation -> 616 val applicableTargets = annotation.targets() 617 // If the annotation is not type use, it has been correctly applied to the item. 618 !applicableTargets.contains(JAVA_LANG_TYPE_USE_TARGET) || 619 // If the annotation has the item type as a target, it should be applied here. 620 applicableTargets.contains(expectedTarget) || 621 // For now, leave in nullness annotations until they are specially handled. 622 isNullnessAnnotation(annotation.qualifiedName.orEmpty()) 623 } 624 } 625 626 private fun createFromPsiElement( 627 codebase: PsiBasedCodebase, 628 element: PsiModifierListOwner 629 ): MutableModifierList { 630 var flags = 631 element.modifierList?.let { modifierList -> computeFlag(element, modifierList) } 632 ?: PACKAGE_PRIVATE 633 634 val psiAnnotations = element.annotations 635 return if (psiAnnotations.isEmpty()) { 636 createMutableModifiers(flags) 637 } else { 638 val annotations = 639 // psi sometimes returns duplicate annotations, using distinct() to counter 640 // that. 641 psiAnnotations 642 .distinct() 643 // Remove any type-use annotations that psi incorrectly applied to the item. 644 .filterIncorrectTypeUseAnnotations(element) 645 .mapNotNull { PsiAnnotationItem.create(codebase, it) } 646 .filter { !it.isDeprecatedForSdk() } 647 createMutableModifiers(flags, annotations) 648 } 649 } 650 651 private fun createFromUAnnotated( 652 codebase: PsiBasedCodebase, 653 element: PsiModifierListOwner, 654 annotated: UAnnotated 655 ): MutableModifierList { 656 val modifierList = 657 element.modifierList ?: return createMutableModifiers(VisibilityLevel.PACKAGE_PRIVATE) 658 val uAnnotations = annotated.uAnnotations 659 val psiAnnotations = 660 modifierList.annotations.takeIf { it.isNotEmpty() } 661 ?: (annotated.javaPsi as? PsiModifierListOwner)?.annotations 662 ?: PsiAnnotation.EMPTY_ARRAY 663 664 var flags = computeFlag(element, modifierList) 665 666 return if (uAnnotations.isEmpty()) { 667 if (psiAnnotations.isNotEmpty()) { 668 val annotations = 669 psiAnnotations.mapNotNull { PsiAnnotationItem.create(codebase, it) } 670 createMutableModifiers(flags, annotations) 671 } else { 672 createMutableModifiers(flags) 673 } 674 } else { 675 val isPrimitiveVariable = element is UVariable && element.type is PsiPrimitiveType 676 677 var annotations = 678 uAnnotations 679 // Uast sometimes puts nullability annotations on primitives!? 680 .filter { 681 !isPrimitiveVariable || 682 it.qualifiedName == null || 683 !it.isKotlinNullabilityAnnotation 684 } 685 .mapNotNull { UAnnotationItem.create(codebase, it) } 686 .filter { !it.isDeprecatedForSdk() } 687 688 if (!isPrimitiveVariable) { 689 if (psiAnnotations.isNotEmpty() && annotations.none { it.isNullnessAnnotation() }) { 690 val ktNullAnnotation = 691 psiAnnotations.firstOrNull { psiAnnotation -> 692 psiAnnotation.qualifiedName?.let { isNullnessAnnotation(it) } == true 693 } 694 ktNullAnnotation?.let { 695 PsiAnnotationItem.create(codebase, it)?.let { annotationItem -> 696 annotations = 697 annotations.toMutableList().run { 698 add(annotationItem) 699 toList() 700 } 701 } 702 } 703 } 704 } 705 706 createMutableModifiers(flags, annotations) 707 } 708 } 709 710 /** Returns whether this is a `@DeprecatedForSdk` annotation **that should be skipped**. */ 711 private fun AnnotationItem.isDeprecatedForSdk(): Boolean { 712 if (qualifiedName != ANDROID_DEPRECATED_FOR_SDK) { 713 return false 714 } 715 716 val allowIn = findAttribute(ATTR_ALLOW_IN) ?: return false 717 718 for (api in allowIn.leafValues()) { 719 val annotationName = api.value() as? String ?: continue 720 if (annotationContext.annotationManager.isShowAnnotationName(annotationName)) { 721 return true 722 } 723 } 724 725 return false 726 } 727 728 private val NOT_NULL = NotNull::class.qualifiedName 729 private val NULLABLE = Nullable::class.qualifiedName 730 731 private val UAnnotation.isKotlinNullabilityAnnotation: Boolean 732 get() = qualifiedName == NOT_NULL || qualifiedName == NULLABLE 733 } 734 735 private const val ATTR_ALLOW_IN = "allowIn" 736