• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.SdkConstants
20 import com.android.SdkConstants.ATTR_VALUE
21 import com.android.SdkConstants.INT_DEF_ANNOTATION
22 import com.android.SdkConstants.LONG_DEF_ANNOTATION
23 import com.android.SdkConstants.STRING_DEF_ANNOTATION
24 import com.android.tools.lint.annotations.Extractor.ANDROID_INT_DEF
25 import com.android.tools.lint.annotations.Extractor.ANDROID_LONG_DEF
26 import com.android.tools.lint.annotations.Extractor.ANDROID_STRING_DEF
27 import com.android.tools.metalava.ANDROIDX_ANNOTATION_PREFIX
28 import com.android.tools.metalava.ANDROIDX_NONNULL
29 import com.android.tools.metalava.ANDROIDX_NULLABLE
30 import com.android.tools.metalava.ANDROID_NONNULL
31 import com.android.tools.metalava.ANDROID_NULLABLE
32 import com.android.tools.metalava.ANDROID_SUPPORT_ANNOTATION_PREFIX
33 import com.android.tools.metalava.Compatibility
34 import com.android.tools.metalava.JAVA_LANG_PREFIX
35 import com.android.tools.metalava.Options
36 import com.android.tools.metalava.RECENTLY_NONNULL
37 import com.android.tools.metalava.RECENTLY_NULLABLE
38 import com.android.tools.metalava.ApiPredicate
39 import com.android.tools.metalava.model.psi.PsiBasedCodebase
40 import com.android.tools.metalava.options
41 import com.intellij.psi.PsiCallExpression
42 import com.intellij.psi.PsiField
43 import com.intellij.psi.PsiModifierListOwner
44 import com.intellij.psi.PsiReference
45 import org.jetbrains.kotlin.psi.KtObjectDeclaration
46 import org.jetbrains.uast.UElement
47 import java.util.function.Predicate
48 
49 fun isNullableAnnotation(qualifiedName: String): Boolean {
50     return qualifiedName.endsWith("Nullable")
51 }
52 
isNonNullAnnotationnull53 fun isNonNullAnnotation(qualifiedName: String): Boolean {
54     return qualifiedName.endsWith("NonNull") ||
55         qualifiedName.endsWith("NotNull") ||
56         qualifiedName.endsWith("Nonnull")
57 }
58 
59 interface AnnotationItem {
60     val codebase: Codebase
61 
62     /** Fully qualified name of the annotation */
qualifiedNamenull63     fun qualifiedName(): String?
64 
65     /** Fully qualified name of the annotation (prior to name mapping) */
66     fun originalName(): String?
67 
68     /** Generates source code for this annotation (using fully qualified names) */
69     fun toSource(
70         target: AnnotationTarget = AnnotationTarget.SIGNATURE_FILE,
71         showDefaultAttrs: Boolean = true
72     ): String
73 
74     /** The applicable targets for this annotation */
75     fun targets(): Set<AnnotationTarget>
76 
77     /** Attributes of the annotation (may be empty) */
78     fun attributes(): List<AnnotationAttribute>
79 
80     /** True if this annotation represents @Nullable or @NonNull (or some synonymous annotation) */
81     fun isNullnessAnnotation(): Boolean {
82         return isNullable() || isNonNull()
83     }
84 
85     /** True if this annotation represents @Nullable (or some synonymous annotation) */
isNullablenull86     fun isNullable(): Boolean {
87         return isNullableAnnotation(qualifiedName() ?: return false)
88     }
89 
90     /** True if this annotation represents @NonNull (or some synonymous annotation) */
isNonNullnull91     fun isNonNull(): Boolean {
92         return isNonNullAnnotation(qualifiedName() ?: return false)
93     }
94 
95     /** True if this annotation represents @IntDef, @LongDef or @StringDef */
isTypeDefAnnotationnull96     fun isTypeDefAnnotation(): Boolean {
97         val name = qualifiedName() ?: return false
98         if (!(name.endsWith("Def"))) {
99             return false
100         }
101         return (INT_DEF_ANNOTATION.isEquals(name) ||
102             STRING_DEF_ANNOTATION.isEquals(name) ||
103             LONG_DEF_ANNOTATION.isEquals(name) ||
104             ANDROID_INT_DEF == name ||
105             ANDROID_STRING_DEF == name ||
106             ANDROID_LONG_DEF == name)
107     }
108 
109     /**
110      * True if this annotation represents a @ParameterName annotation (or some synonymous annotation).
111      * The parameter name should be the default attribute or "value".
112      */
isParameterNamenull113     fun isParameterName(): Boolean {
114         return qualifiedName()?.endsWith(".ParameterName") ?: return false
115     }
116 
117     /**
118      * True if this annotation represents a @DefaultValue annotation (or some synonymous annotation).
119      * The default value should be the default attribute or "value".
120      */
isDefaultValuenull121     fun isDefaultValue(): Boolean {
122         return qualifiedName()?.endsWith(".DefaultValue") ?: return false
123     }
124 
125     /** Returns the given named attribute if specified */
findAttributenull126     fun findAttribute(name: String?): AnnotationAttribute? {
127         val actualName = name ?: ATTR_VALUE
128         return attributes().firstOrNull { it.name == actualName }
129     }
130 
131     /** Find the class declaration for the given annotation */
resolvenull132     fun resolve(): ClassItem? {
133         return codebase.findClass(qualifiedName() ?: return null)
134     }
135 
136     /** If this annotation has a typedef annotation associated with it, return it */
findTypedefAnnotationnull137     fun findTypedefAnnotation(): AnnotationItem? {
138         val className = originalName() ?: return null
139         return codebase.findClass(className)?.modifiers?.annotations()?.firstOrNull { it.isTypeDefAnnotation() }
140     }
141 
142     /** Returns the retention of this annotation */
143     val retention: AnnotationRetention
144         get() {
145             val name = qualifiedName()
146             if (name != null) {
147                 val cls = codebase.findClass(name) ?: (codebase as? PsiBasedCodebase)?.findOrCreateClass(name)
148                 if (cls != null) {
149                     if (cls.isAnnotationType()) {
150                         return cls.getRetention()
151                     }
152                 }
153             }
154 
155             return AnnotationRetention.CLASS
156         }
157 
158     companion object {
159         /** The simple name of an annotation, which is the annotation name (not qualified name) prefixed by @ */
simpleNamenull160         fun simpleName(item: AnnotationItem): String {
161             val qualifiedName = item.qualifiedName() ?: return ""
162             return "@${qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1)}"
163         }
164 
165         /**
166          * Maps an annotation name to the name to be used in signatures/stubs/external annotation files.
167          * Annotations that should not be exported are mapped to null.
168          */
mapNamenull169         fun mapName(
170             codebase: Codebase,
171             qualifiedName: String?,
172             filter: Predicate<Item>? = null,
173             target: AnnotationTarget = AnnotationTarget.SIGNATURE_FILE
174         ): String? {
175             qualifiedName ?: return null
176             if (options.passThroughAnnotations.contains(qualifiedName)) {
177                 return qualifiedName
178             }
179             if (options.excludeAnnotations.contains(qualifiedName)) {
180                 return null
181             }
182             when (qualifiedName) {
183                 // Resource annotations
184                 "android.support.annotation.AnimRes",
185                 "android.annotation.AnimRes" -> return "androidx.annotation.AnimRes"
186                 "android.support.annotation.AnimatorRes",
187                 "android.annotation.AnimatorRes" -> return "androidx.annotation.AnimatorRes"
188                 "android.support.annotation.AnyRes",
189                 "android.annotation.AnyRes" -> return "androidx.annotation.AnyRes"
190                 "android.support.annotation.ArrayRes",
191                 "android.annotation.ArrayRes" -> return "androidx.annotation.ArrayRes"
192                 "android.support.annotation.AttrRes",
193                 "android.annotation.AttrRes" -> return "androidx.annotation.AttrRes"
194                 "android.support.annotation.BoolRes",
195                 "android.annotation.BoolRes" -> return "androidx.annotation.BoolRes"
196                 "android.support.annotation.ColorRes",
197                 "android.annotation.ColorRes" -> return "androidx.annotation.ColorRes"
198                 "android.support.annotation.DimenRes",
199                 "android.annotation.DimenRes" -> return "androidx.annotation.DimenRes"
200                 "android.support.annotation.DrawableRes",
201                 "android.annotation.DrawableRes" -> return "androidx.annotation.DrawableRes"
202                 "android.support.annotation.FontRes",
203                 "android.annotation.FontRes" -> return "androidx.annotation.FontRes"
204                 "android.support.annotation.FractionRes",
205                 "android.annotation.FractionRes" -> return "androidx.annotation.FractionRes"
206                 "android.support.annotation.IdRes",
207                 "android.annotation.IdRes" -> return "androidx.annotation.IdRes"
208                 "android.support.annotation.IntegerRes",
209                 "android.annotation.IntegerRes" -> return "androidx.annotation.IntegerRes"
210                 "android.support.annotation.InterpolatorRes",
211                 "android.annotation.InterpolatorRes" -> return "androidx.annotation.InterpolatorRes"
212                 "android.support.annotation.LayoutRes",
213                 "android.annotation.LayoutRes" -> return "androidx.annotation.LayoutRes"
214                 "android.support.annotation.MenuRes",
215                 "android.annotation.MenuRes" -> return "androidx.annotation.MenuRes"
216                 "android.support.annotation.PluralsRes",
217                 "android.annotation.PluralsRes" -> return "androidx.annotation.PluralsRes"
218                 "android.support.annotation.RawRes",
219                 "android.annotation.RawRes" -> return "androidx.annotation.RawRes"
220                 "android.support.annotation.StringRes",
221                 "android.annotation.StringRes" -> return "androidx.annotation.StringRes"
222                 "android.support.annotation.StyleRes",
223                 "android.annotation.StyleRes" -> return "androidx.annotation.StyleRes"
224                 "android.support.annotation.StyleableRes",
225                 "android.annotation.StyleableRes" -> return "androidx.annotation.StyleableRes"
226                 "android.support.annotation.TransitionRes",
227                 "android.annotation.TransitionRes" -> return "androidx.annotation.TransitionRes"
228                 "android.support.annotation.XmlRes",
229                 "android.annotation.XmlRes" -> return "androidx.annotation.XmlRes"
230 
231                 // Threading
232                 "android.support.annotation.AnyThread",
233                 "android.annotation.AnyThread" -> return "androidx.annotation.AnyThread"
234                 "android.support.annotation.BinderThread",
235                 "android.annotation.BinderThread" -> return "androidx.annotation.BinderThread"
236                 "android.support.annotation.MainThread",
237                 "android.annotation.MainThread" -> return "androidx.annotation.MainThread"
238                 "android.support.annotation.UiThread",
239                 "android.annotation.UiThread" -> return "androidx.annotation.UiThread"
240                 "android.support.annotation.WorkerThread",
241                 "android.annotation.WorkerThread" -> return "androidx.annotation.WorkerThread"
242 
243                 // Colors
244                 "android.support.annotation.ColorInt",
245                 "android.annotation.ColorInt" -> return "androidx.annotation.ColorInt"
246                 "android.support.annotation.ColorLong",
247                 "android.annotation.ColorLong" -> return "androidx.annotation.ColorLong"
248                 "android.support.annotation.HalfFloat",
249                 "android.annotation.HalfFloat" -> return "androidx.annotation.HalfFloat"
250 
251                 // Ranges and sizes
252                 "android.support.annotation.FloatRange",
253                 "android.annotation.FloatRange" -> return "androidx.annotation.FloatRange"
254                 "android.support.annotation.IntRange",
255                 "android.annotation.IntRange" -> return "androidx.annotation.IntRange"
256                 "android.support.annotation.Size",
257                 "android.annotation.Size" -> return "androidx.annotation.Size"
258                 "android.support.annotation.Px",
259                 "android.annotation.Px" -> return "androidx.annotation.Px"
260                 "android.support.annotation.Dimension",
261                 "android.annotation.Dimension" -> return "androidx.annotation.Dimension"
262 
263                 // Null
264                 // We only change recently/newly nullable annotation in stubs
265                 RECENTLY_NULLABLE -> return if (target == AnnotationTarget.SDK_STUBS_FILE) qualifiedName else ANDROIDX_NULLABLE
266                 RECENTLY_NONNULL -> return if (target == AnnotationTarget.SDK_STUBS_FILE) qualifiedName else ANDROIDX_NONNULL
267 
268                 ANDROIDX_NULLABLE,
269                 ANDROID_NULLABLE,
270                 "android.support.annotation.Nullable",
271                 "libcore.util.Nullable",
272                 "org.jetbrains.annotations.Nullable" -> return nullableAnnotationName(target)
273 
274                 ANDROIDX_NONNULL,
275                 ANDROID_NONNULL,
276                 "android.support.annotation.NonNull",
277                 "libcore.util.NonNull",
278                 "org.jetbrains.annotations.NotNull" -> return nonNullAnnotationName(target)
279 
280                 // Typedefs
281                 "android.support.annotation.IntDef",
282                 "android.annotation.IntDef" -> return "androidx.annotation.IntDef"
283                 "android.support.annotation.StringDef",
284                 "android.annotation.StringDef" -> return "androidx.annotation.StringDef"
285                 "android.support.annotation.LongDef",
286                 "android.annotation.LongDef" -> return "androidx.annotation.LongDef"
287 
288                 // Context Types
289                 "android.annotation.UiContext" -> return "androidx.annotation.UiContext"
290                 "android.annotation.DisplayContext" -> return "androidx.annotation.DisplayContext"
291                 "android.annotation.NonUiContext" -> return "androidx.annotation.NonUiContext"
292 
293                 // Misc
294                 "android.support.annotation.CallSuper",
295                 "android.annotation.CallSuper" -> return "androidx.annotation.CallSuper"
296                 "android.support.annotation.CheckResult",
297                 "android.annotation.CheckResult" -> return "androidx.annotation.CheckResult"
298                 "android.support.annotation.RequiresPermission",
299                 "android.annotation.RequiresPermission" -> return "androidx.annotation.RequiresPermission"
300                 "android.annotation.RequiresPermission.Read" -> return "androidx.annotation.RequiresPermission.Read"
301                 "android.annotation.RequiresPermission.Write" -> return "androidx.annotation.RequiresPermission.Write"
302 
303                 // These aren't support annotations, but could/should be:
304                 "android.annotation.CurrentTimeMillisLong",
305                 "android.annotation.DurationMillisLong",
306                 "android.annotation.ElapsedRealtimeLong",
307                 "android.annotation.UserIdInt",
308                 "android.annotation.BytesLong",
309 
310                 // These aren't support annotations
311                 "android.annotation.AppIdInt",
312                 "android.annotation.SuppressAutoDoc",
313                 "android.annotation.SystemApi",
314                 "android.annotation.TestApi",
315                 "android.annotation.CallbackExecutor",
316                 "android.annotation.Condemned",
317                 "android.annotation.Hide",
318 
319                 "android.annotation.Widget" -> {
320                     // Remove, unless (a) public or (b) specifically included in --showAnnotations
321                     return if (options.showAnnotations.matches(qualifiedName)) {
322                         qualifiedName
323                     } else if (filter != null) {
324                         val cls = codebase.findClass(qualifiedName)
325                         if (cls != null && filter.test(cls)) {
326                             qualifiedName
327                         } else {
328                             null
329                         }
330                     } else {
331                         qualifiedName
332                     }
333                 }
334 
335                 // Included for analysis, but should not be exported:
336                 "android.annotation.BroadcastBehavior",
337                 "android.annotation.SdkConstant",
338                 "android.annotation.RequiresFeature",
339                 "android.annotation.SystemService" -> return qualifiedName
340 
341                 // Should not be mapped to a different package name:
342                 "android.annotation.TargetApi",
343                 "android.annotation.SuppressLint" -> return qualifiedName
344 
345                 else -> {
346                     // Some new annotations added to the platform: assume they are support annotations?
347                     return when {
348                         // Special Kotlin annotations recognized by the compiler: map to supported package name
349                         qualifiedName.endsWith(".ParameterName") || qualifiedName.endsWith(".DefaultValue") ->
350                             "kotlin.annotations.jvm.internal${qualifiedName.substring(qualifiedName.lastIndexOf('.'))}"
351 
352                         // Other third party nullness annotations?
353                         isNullableAnnotation(qualifiedName) -> nullableAnnotationName(target)
354                         isNonNullAnnotation(qualifiedName) -> nonNullAnnotationName(target)
355 
356                         // Support library annotations are all included, as is the built-in stuff like @Retention
357                         qualifiedName.startsWith(ANDROIDX_ANNOTATION_PREFIX) -> return qualifiedName
358                         qualifiedName.startsWith(JAVA_LANG_PREFIX) -> return qualifiedName
359 
360                         // Unknown Android platform annotations
361                         qualifiedName.startsWith("android.annotation.") -> {
362                             // Remove, unless specifically included in --showAnnotations
363                             return if (options.showAnnotations.matches(qualifiedName)) {
364                                 qualifiedName
365                             } else {
366                                 null
367                             }
368                         }
369 
370                         qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) -> {
371                             return mapName(
372                                 codebase,
373                                 ANDROIDX_ANNOTATION_PREFIX + qualifiedName.substring(ANDROID_SUPPORT_ANNOTATION_PREFIX.length),
374                                 filter,
375                                 target
376                             )
377                         }
378 
379                         else -> {
380                             // Remove, unless (a) public or (b) specifically included in --showAnnotations
381                             return if (options.showAnnotations.matches(qualifiedName)) {
382                                 qualifiedName
383                             } else if (filter != null) {
384                                 val cls = codebase.findClass(qualifiedName)
385                                 if (cls != null && filter.test(cls)) {
386                                     qualifiedName
387                                 } else {
388                                     null
389                                 }
390                             } else {
391                                 qualifiedName
392                             }
393                         }
394                     }
395                 }
396             }
397         }
398 
nullableAnnotationNamenull399         private fun nullableAnnotationName(target: AnnotationTarget) =
400             if (target == AnnotationTarget.SDK_STUBS_FILE) ANDROID_NULLABLE else ANDROIDX_NULLABLE
401 
402         private fun nonNullAnnotationName(target: AnnotationTarget) =
403             if (target == AnnotationTarget.SDK_STUBS_FILE) ANDROID_NONNULL else ANDROIDX_NONNULL
404 
405         private val TYPEDEF_ANNOTATION_TARGETS =
406             if (options.typedefMode == Options.TypedefMode.INLINE ||
407                 options.typedefMode == Options.TypedefMode.NONE) // just here for compatibility purposes
408                 ANNOTATION_EXTERNAL
409             else
410                 ANNOTATION_EXTERNAL_ONLY
411 
412         /** The applicable targets for this annotation */
413         fun computeTargets(
414             annotation: AnnotationItem,
415             classFinder: (String) -> ClassItem?
416         ): Set<AnnotationTarget> {
417             val qualifiedName = annotation.qualifiedName() ?: return NO_ANNOTATION_TARGETS
418             if (options.passThroughAnnotations.contains(qualifiedName)) {
419                 return ANNOTATION_IN_ALL_STUBS
420             }
421             when (qualifiedName) {
422 
423                 // The typedef annotations are special: they should not be in the signature
424                 // files, but we want to include them in the external annotations file such that tools
425                 // can enforce them.
426                 "android.support.annotation.IntDef",
427                 "android.annotation.IntDef",
428                 "androidx.annotation.IntDef",
429                 "android.support.annotation.StringDef",
430                 "android.annotation.StringDef",
431                 "androidx.annotation.StringDef",
432                 "android.support.annotation.LongDef",
433                 "android.annotation.LongDef",
434                 "androidx.annotation.LongDef" -> return TYPEDEF_ANNOTATION_TARGETS
435 
436                 // Not directly API relevant
437                 "android.view.ViewDebug.ExportedProperty",
438                 "android.view.ViewDebug.CapturedViewProperty" -> return ANNOTATION_STUBS_ONLY
439 
440                 // Skip known annotations that we (a) never want in external annotations and (b) we are
441                 // specially overwriting anyway in the stubs (and which are (c) not API significant)
442                 "com.android.modules.annotation.MinSdk",
443                 "java.lang.annotation.Native",
444                 "java.lang.SuppressWarnings",
445                 "java.lang.Override",
446                 "kotlin.Suppress",
447                 "androidx.annotation.experimental.UseExperimental",
448                 "androidx.annotation.OptIn",
449                 "kotlin.UseExperimental",
450                 "kotlin.OptIn" -> return NO_ANNOTATION_TARGETS
451 
452                 // TODO(aurimas): consider using annotation directly instead of modifiers
453                 "kotlin.Deprecated" -> return NO_ANNOTATION_TARGETS // tracked separately as a pseudo-modifier
454                 "java.lang.Deprecated", // tracked separately as a pseudo-modifier
455 
456                 // Below this when-statement we perform the correct lookup: check API predicate, and check
457                 // that retention is class or runtime, but we've hardcoded the answers here
458                 // for some common annotations.
459 
460                 "android.widget.RemoteViews.RemoteView",
461 
462                 "kotlin.annotation.Target",
463                 "kotlin.annotation.Retention",
464                 "kotlin.annotation.Repeatable",
465                 "kotlin.annotation.MustBeDocumented",
466                 "kotlin.DslMarker",
467                 "kotlin.PublishedApi",
468                 "kotlin.ExtensionFunctionType",
469 
470                 "java.lang.FunctionalInterface",
471                 "java.lang.SafeVarargs",
472                 "java.lang.annotation.Documented",
473                 "java.lang.annotation.Inherited",
474                 "java.lang.annotation.Repeatable",
475                 "java.lang.annotation.Retention",
476                 "java.lang.annotation.Target" -> return ANNOTATION_IN_ALL_STUBS
477 
478                 // Metalava already tracks all the methods that get generated due to these annotations.
479                 "kotlin.jvm.JvmOverloads",
480                 "kotlin.jvm.JvmField",
481                 "kotlin.jvm.JvmStatic",
482                 "kotlin.jvm.JvmName" -> return NO_ANNOTATION_TARGETS
483             }
484 
485             // @android.annotation.Nullable and NonNullable specially recognized annotations by the Kotlin
486             // compiler 1.3 and above: they always go in the stubs.
487             if (qualifiedName == ANDROID_NULLABLE ||
488                 qualifiedName == ANDROID_NONNULL ||
489                 qualifiedName == ANDROIDX_NULLABLE ||
490                 qualifiedName == ANDROIDX_NONNULL
491             ) {
492                 return ANNOTATION_IN_ALL_STUBS
493             }
494 
495             if (qualifiedName.startsWith("android.annotation.")) {
496                 // internal annotations not mapped to androidx: things like @SystemApi. Skip from
497                 // stubs, external annotations, signature files, etc.
498                 return NO_ANNOTATION_TARGETS
499             }
500 
501             // @RecentlyNullable and @RecentlyNonNull are specially recognized annotations by the Kotlin
502             // compiler: they always go in the stubs.
503             if (qualifiedName == RECENTLY_NULLABLE ||
504                 qualifiedName == RECENTLY_NONNULL
505             ) {
506                 return ANNOTATION_IN_ALL_STUBS
507             }
508 
509             // Determine the retention of the annotation: source retention annotations go
510             // in the external annotations file, class and runtime annotations go in
511             // the stubs files (except for the androidx annotations which are not included
512             // in the SDK and therefore cannot be referenced from it due to apt's unfortunate
513             // habit of loading all annotation classes it encounters.)
514 
515             if (qualifiedName.startsWith("androidx.annotation.")) {
516                 if (options.includeSourceRetentionAnnotations) {
517                     return ANNOTATION_IN_ALL_STUBS
518                 }
519 
520                 if (qualifiedName == ANDROIDX_NULLABLE || qualifiedName == ANDROIDX_NONNULL) {
521                     // Right now, nullness annotations (other than @RecentlyNullable and @RecentlyNonNull)
522                     // have to go in external annotations since they aren't in the class path for
523                     // annotation processors. However, we do want them showing up in the documentation using
524                     // their real annotation names.
525                     return ANNOTATION_IN_DOC_STUBS_AND_EXTERNAL
526                 }
527 
528                 return ANNOTATION_EXTERNAL
529             }
530 
531             // See if the annotation is pointing to an annotation class that is part of the API; if not, skip it.
532             val cls = classFinder(qualifiedName) ?: return NO_ANNOTATION_TARGETS
533             if (!ApiPredicate().test(cls)) {
534                 if (options.typedefMode != Options.TypedefMode.NONE) {
535                     if (cls.modifiers.annotations().any { it.isTypeDefAnnotation() }) {
536                         return ANNOTATION_SIGNATURE_ONLY
537                     }
538                 }
539 
540                 return NO_ANNOTATION_TARGETS
541             }
542 
543             if (cls.isAnnotationType()) {
544                 val retention = cls.getRetention()
545                 if (retention == AnnotationRetention.RUNTIME || retention == AnnotationRetention.CLASS) {
546                     return ANNOTATION_IN_ALL_STUBS
547                 }
548             }
549 
550             return ANNOTATION_EXTERNAL
551         }
552 
553         /**
554          * Given a "full" annotation name, shortens it by removing redundant package names.
555          * This is intended to be used by the [Compatibility.omitCommonPackages] flag
556          * to reduce clutter in signature files.
557          *
558          * For example, this method will convert `@androidx.annotation.Nullable` to just
559          * `@Nullable`, and `@androidx.annotation.IntRange(from=20)` to `IntRange(from=20)`.
560          */
shortenAnnotationnull561         fun shortenAnnotation(source: String): String {
562             return when {
563                 source == "@java.lang.Deprecated" -> "@Deprecated"
564                 source.startsWith("android.annotation.", 1) -> {
565                     "@" + source.substring("@android.annotation.".length)
566                 }
567                 source.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX, 1) -> {
568                     "@" + source.substring("@android.support.annotation.".length)
569                 }
570                 source.startsWith(ANDROIDX_ANNOTATION_PREFIX, 1) -> {
571                     "@" + source.substring("@androidx.annotation.".length)
572                 }
573                 else -> source
574             }
575         }
576 
577         /**
578          * Reverses the [shortenAnnotation] method. Intended for use when reading in signature files
579          * that contain shortened type references.
580          */
unshortenAnnotationnull581         fun unshortenAnnotation(source: String): String {
582             return when {
583                 source == "@Deprecated" -> "@java.lang.Deprecated"
584                 // These 3 annotations are in the android.annotation. package, not android.support.annotation
585                 source.startsWith("@SystemService") ||
586                     source.startsWith("@TargetApi") ||
587                     source.startsWith("@SuppressLint") ->
588                     "@android.annotation." + source.substring(1)
589                 // If the first character of the name (after "@") is lower-case, then
590                 // assume it's a package name, so no need to shorten it.
591                 source.startsWith("@") && source[1].isLowerCase() -> source
592                 else -> {
593                     "@androidx.annotation." + source.substring(1)
594                 }
595             }
596         }
597 
598         /**
599          * If the given element has an *implicit* nullness, return it. This returns
600          * true for implicitly nullable elements, such as the parameter to the equals
601          * method, false for implicitly non null elements (such as annotation type
602          * members), and null if there is no implicit nullness.
603          */
getImplicitNullnessnull604         fun getImplicitNullness(item: Item): Boolean? {
605             var nullable: Boolean? = null
606 
607             // Is this a Kotlin object declaration (such as a companion object) ?
608             // If so, it is always non null.
609             val sourcePsi = item.psi()
610             if (sourcePsi is UElement && sourcePsi.sourcePsi is KtObjectDeclaration) {
611                 nullable = false
612             }
613 
614             // Constant field not initialized to null?
615             if (item is FieldItem &&
616                 (item.isEnumConstant() || item.modifiers.isFinal() && item.initialValue(false) != null)
617             ) {
618                 // Assigned to constant: not nullable
619                 nullable = false
620             } else if (item is FieldItem && item.modifiers.isFinal()) {
621                 // If we're looking at a final field, look at the right hand side
622                 // of the field to the field initialization. If that right hand side
623                 // for example represents a method call, and the method we're calling
624                 // is annotated with @NonNull, then the field (since it is final) will
625                 // always be @NonNull as well.
626                 val initializer = (item.psi() as? PsiField)?.initializer
627                 if (initializer != null && initializer is PsiReference) {
628                     val resolved = initializer.resolve()
629                     if (resolved is PsiModifierListOwner &&
630                         resolved.annotations.any {
631                             isNonNullAnnotation(it.qualifiedName ?: "")
632                         }
633                     ) {
634                         nullable = false
635                     }
636                 } else if (initializer != null && initializer is PsiCallExpression) {
637                     val resolved = initializer.resolveMethod()
638                     if (resolved != null &&
639                         resolved.annotations.any {
640                             isNonNullAnnotation(it.qualifiedName ?: "")
641                         }
642                     ) {
643                         nullable = false
644                     }
645                 }
646             } else if (item.synthetic && (item is MethodItem && item.isEnumSyntheticMethod() ||
647                     item is ParameterItem && item.containingMethod().isEnumSyntheticMethod())
648             ) {
649                 // Workaround the fact that the Kotlin synthetic enum methods
650                 // do not have nullness information
651                 nullable = false
652             }
653 
654             // Annotation type members cannot be null
655             if (item is MemberItem && item.containingClass().isAnnotationType()) {
656                 nullable = false
657             }
658 
659             // Equals and toString have known nullness
660             if (item is MethodItem && item.name() == "toString" && item.parameters().isEmpty()) {
661                 nullable = false
662             } else if (item is ParameterItem && item.containingMethod().name() == "equals" &&
663                 item.containingMethod().parameters().size == 1
664             ) {
665                 nullable = true
666             }
667 
668             return nullable
669         }
670     }
671 }
672 
673 /** Default implementation of an annotation item */
674 abstract class DefaultAnnotationItem(override val codebase: Codebase) : AnnotationItem {
675     protected var targets: Set<AnnotationTarget>? = null
676 
targetsnull677     override fun targets(): Set<AnnotationTarget> {
678         if (targets == null) {
679             targets = AnnotationItem.computeTargets(this) { className ->
680                 codebase.findClass(className)
681             }
682         }
683         return targets!!
684     }
685 }
686 
687 /** An attribute of an annotation, such as "value" */
688 interface AnnotationAttribute {
689     /** The name of the annotation */
690     val name: String
691     /** The annotation value */
692     val value: AnnotationAttributeValue
693 
694     /**
695      * Return all leaf values; this flattens the complication of handling
696      * {@code @SuppressLint("warning")} and {@code @SuppressLint({"warning1","warning2"})
697      */
leafValuesnull698     fun leafValues(): List<AnnotationAttributeValue> {
699         val result = mutableListOf<AnnotationAttributeValue>()
700         AnnotationAttributeValue.addValues(value, result)
701         return result
702     }
703 }
704 
705 /** An annotation value */
706 interface AnnotationAttributeValue {
707     /** Generates source code for this annotation value */
toSourcenull708     fun toSource(): String
709 
710     /** The value of the annotation */
711     fun value(): Any?
712 
713     /** If the annotation declaration references a field (or class etc), return the resolved class */
714     fun resolve(): Item?
715 
716     companion object {
717         fun addValues(value: AnnotationAttributeValue, into: MutableList<AnnotationAttributeValue>) {
718             if (value is AnnotationArrayAttributeValue) {
719                 for (v in value.values) {
720                     addValues(v, into)
721                 }
722             } else if (value is AnnotationSingleAttributeValue) {
723                 into.add(value)
724             }
725         }
726     }
727 }
728 
729 /** An annotation value (for a single item, not an array) */
730 interface AnnotationSingleAttributeValue : AnnotationAttributeValue {
731     /** The annotation value, expressed as source code */
732     val valueSource: String
733     /** The annotation value */
734     val value: Any?
735 
valuenull736     override fun value() = value
737 }
738 
739 /** An annotation value for an array of items */
740 interface AnnotationArrayAttributeValue : AnnotationAttributeValue {
741     /** The annotation values */
742     val values: List<AnnotationAttributeValue>
743 
744     override fun resolve(): Item? {
745         error("resolve() should not be called on an array value")
746     }
747 
748     override fun value() = values.mapNotNull { it.value() }.toTypedArray()
749 }
750 
751 class DefaultAnnotationAttribute(
752     override val name: String,
753     override val value: DefaultAnnotationValue
754 ) : AnnotationAttribute {
755     companion object {
createnull756         fun create(name: String, value: String): DefaultAnnotationAttribute {
757             return DefaultAnnotationAttribute(name, DefaultAnnotationValue.create(value))
758         }
759 
createListnull760         fun createList(source: String): List<AnnotationAttribute> {
761             val list = mutableListOf<AnnotationAttribute>() // TODO: default size = 2
762             var begin = 0
763             var index = 0
764             val length = source.length
765             while (index < length) {
766                 val c = source[index]
767                 if (c == '{') {
768                     index = findEnd(source, index + 1, length, '}')
769                 } else if (c == '"') {
770                     index = findEnd(source, index + 1, length, '"')
771                 } else if (c == ',') {
772                     addAttribute(list, source, begin, index)
773                     index++
774                     begin = index
775                     continue
776                 } else if (c == ' ' && index == begin) {
777                     begin++
778                 }
779 
780                 index++
781             }
782 
783             if (begin < length) {
784                 addAttribute(list, source, begin, length)
785             }
786 
787             return list
788         }
789 
findEndnull790         private fun findEnd(source: String, from: Int, to: Int, sentinel: Char): Int {
791             var i = from
792             while (i < to) {
793                 val c = source[i]
794                 if (c == '\\') {
795                     i++
796                 } else if (c == sentinel) {
797                     return i
798                 }
799                 i++
800             }
801             return to
802         }
803 
addAttributenull804         private fun addAttribute(list: MutableList<AnnotationAttribute>, source: String, from: Int, to: Int) {
805             var split = source.indexOf('=', from)
806             if (split >= to) {
807                 split = -1
808             }
809             val name: String
810             val value: String
811             val valueBegin: Int
812             val valueEnd: Int
813             if (split == -1) {
814                 valueBegin = split + 1
815                 valueEnd = to
816                 name = "value"
817             } else {
818                 name = source.substring(from, split).trim()
819                 valueBegin = split + 1
820                 valueEnd = to
821             }
822             value = source.substring(valueBegin, valueEnd).trim()
823             list.add(DefaultAnnotationAttribute.create(name, value))
824         }
825     }
826 
toStringnull827     override fun toString(): String {
828         return "DefaultAnnotationAttribute(name='$name', value=$value)"
829     }
830 }
831 
832 abstract class DefaultAnnotationValue : AnnotationAttributeValue {
833     companion object {
createnull834         fun create(value: String): DefaultAnnotationValue {
835             return if (value.startsWith("{")) { // Array
836                 DefaultAnnotationArrayAttributeValue(value)
837             } else {
838                 DefaultAnnotationSingleAttributeValue(value)
839             }
840         }
841     }
842 
toStringnull843     override fun toString(): String = toSource()
844 }
845 
846 class DefaultAnnotationSingleAttributeValue(override val valueSource: String) : DefaultAnnotationValue(),
847     AnnotationSingleAttributeValue {
848     @Suppress("IMPLICIT_CAST_TO_ANY")
849     override val value = when {
850         valueSource == SdkConstants.VALUE_TRUE -> true
851         valueSource == SdkConstants.VALUE_FALSE -> false
852         valueSource.startsWith("\"") -> valueSource.removeSurrounding("\"")
853         valueSource.startsWith('\'') -> valueSource.removeSurrounding("'")[0]
854         else -> try {
855             if (valueSource.contains(".")) {
856                 valueSource.toDouble()
857             } else {
858                 valueSource.toLong()
859             }
860         } catch (e: NumberFormatException) {
861             valueSource
862         }
863     }
864 
865     override fun resolve(): Item? = null
866 
867     override fun toSource() = valueSource
868 }
869 
870 class DefaultAnnotationArrayAttributeValue(val value: String) : DefaultAnnotationValue(),
871     AnnotationArrayAttributeValue {
872     init {
<lambda>null873         assert(value.startsWith("{") && value.endsWith("}")) { value }
874     }
875 
<lambda>null876     override val values = value.substring(1, value.length - 1).split(",").map {
877         DefaultAnnotationValue.create(it.trim())
878     }.toList()
879 
toSourcenull880     override fun toSource() = value
881 }
882