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.doclava1.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             when (qualifiedName) {
180                 // Resource annotations
181                 "android.support.annotation.AnimRes",
182                 "android.annotation.AnimRes" -> return "androidx.annotation.AnimRes"
183                 "android.support.annotation.AnimatorRes",
184                 "android.annotation.AnimatorRes" -> return "androidx.annotation.AnimatorRes"
185                 "android.support.annotation.AnyRes",
186                 "android.annotation.AnyRes" -> return "androidx.annotation.AnyRes"
187                 "android.support.annotation.ArrayRes",
188                 "android.annotation.ArrayRes" -> return "androidx.annotation.ArrayRes"
189                 "android.support.annotation.AttrRes",
190                 "android.annotation.AttrRes" -> return "androidx.annotation.AttrRes"
191                 "android.support.annotation.BoolRes",
192                 "android.annotation.BoolRes" -> return "androidx.annotation.BoolRes"
193                 "android.support.annotation.ColorRes",
194                 "android.annotation.ColorRes" -> return "androidx.annotation.ColorRes"
195                 "android.support.annotation.DimenRes",
196                 "android.annotation.DimenRes" -> return "androidx.annotation.DimenRes"
197                 "android.support.annotation.DrawableRes",
198                 "android.annotation.DrawableRes" -> return "androidx.annotation.DrawableRes"
199                 "android.support.annotation.FontRes",
200                 "android.annotation.FontRes" -> return "androidx.annotation.FontRes"
201                 "android.support.annotation.FractionRes",
202                 "android.annotation.FractionRes" -> return "androidx.annotation.FractionRes"
203                 "android.support.annotation.IdRes",
204                 "android.annotation.IdRes" -> return "androidx.annotation.IdRes"
205                 "android.support.annotation.IntegerRes",
206                 "android.annotation.IntegerRes" -> return "androidx.annotation.IntegerRes"
207                 "android.support.annotation.InterpolatorRes",
208                 "android.annotation.InterpolatorRes" -> return "androidx.annotation.InterpolatorRes"
209                 "android.support.annotation.LayoutRes",
210                 "android.annotation.LayoutRes" -> return "androidx.annotation.LayoutRes"
211                 "android.support.annotation.MenuRes",
212                 "android.annotation.MenuRes" -> return "androidx.annotation.MenuRes"
213                 "android.support.annotation.PluralsRes",
214                 "android.annotation.PluralsRes" -> return "androidx.annotation.PluralsRes"
215                 "android.support.annotation.RawRes",
216                 "android.annotation.RawRes" -> return "androidx.annotation.RawRes"
217                 "android.support.annotation.StringRes",
218                 "android.annotation.StringRes" -> return "androidx.annotation.StringRes"
219                 "android.support.annotation.StyleRes",
220                 "android.annotation.StyleRes" -> return "androidx.annotation.StyleRes"
221                 "android.support.annotation.StyleableRes",
222                 "android.annotation.StyleableRes" -> return "androidx.annotation.StyleableRes"
223                 "android.support.annotation.TransitionRes",
224                 "android.annotation.TransitionRes" -> return "androidx.annotation.TransitionRes"
225                 "android.support.annotation.XmlRes",
226                 "android.annotation.XmlRes" -> return "androidx.annotation.XmlRes"
227 
228                 // Threading
229                 "android.support.annotation.AnyThread",
230                 "android.annotation.AnyThread" -> return "androidx.annotation.AnyThread"
231                 "android.support.annotation.BinderThread",
232                 "android.annotation.BinderThread" -> return "androidx.annotation.BinderThread"
233                 "android.support.annotation.MainThread",
234                 "android.annotation.MainThread" -> return "androidx.annotation.MainThread"
235                 "android.support.annotation.UiThread",
236                 "android.annotation.UiThread" -> return "androidx.annotation.UiThread"
237                 "android.support.annotation.WorkerThread",
238                 "android.annotation.WorkerThread" -> return "androidx.annotation.WorkerThread"
239 
240                 // Colors
241                 "android.support.annotation.ColorInt",
242                 "android.annotation.ColorInt" -> return "androidx.annotation.ColorInt"
243                 "android.support.annotation.ColorLong",
244                 "android.annotation.ColorLong" -> return "androidx.annotation.ColorLong"
245                 "android.support.annotation.HalfFloat",
246                 "android.annotation.HalfFloat" -> return "androidx.annotation.HalfFloat"
247 
248                 // Ranges and sizes
249                 "android.support.annotation.FloatRange",
250                 "android.annotation.FloatRange" -> return "androidx.annotation.FloatRange"
251                 "android.support.annotation.IntRange",
252                 "android.annotation.IntRange" -> return "androidx.annotation.IntRange"
253                 "android.support.annotation.Size",
254                 "android.annotation.Size" -> return "androidx.annotation.Size"
255                 "android.support.annotation.Px",
256                 "android.annotation.Px" -> return "androidx.annotation.Px"
257                 "android.support.annotation.Dimension",
258                 "android.annotation.Dimension" -> return "androidx.annotation.Dimension"
259 
260                 // Null
261                 // We only change recently/newly nullable annotation in stubs
262                 RECENTLY_NULLABLE -> return if (target == AnnotationTarget.SDK_STUBS_FILE) qualifiedName else ANDROIDX_NULLABLE
263                 RECENTLY_NONNULL -> return if (target == AnnotationTarget.SDK_STUBS_FILE) qualifiedName else ANDROIDX_NONNULL
264 
265                 ANDROIDX_NULLABLE,
266                 ANDROID_NULLABLE,
267                 "android.support.annotation.Nullable",
268                 "libcore.util.Nullable",
269                 "org.jetbrains.annotations.Nullable" -> return nullableAnnotationName(target)
270 
271                 ANDROIDX_NONNULL,
272                 ANDROID_NONNULL,
273                 "android.support.annotation.NonNull",
274                 "libcore.util.NonNull",
275                 "org.jetbrains.annotations.NotNull" -> return nonNullAnnotationName(target)
276 
277                 // Typedefs
278                 "android.support.annotation.IntDef",
279                 "android.annotation.IntDef" -> return "androidx.annotation.IntDef"
280                 "android.support.annotation.StringDef",
281                 "android.annotation.StringDef" -> return "androidx.annotation.StringDef"
282                 "android.support.annotation.LongDef",
283                 "android.annotation.LongDef" -> return "androidx.annotation.LongDef"
284 
285                 // Misc
286                 "android.support.annotation.CallSuper",
287                 "android.annotation.CallSuper" -> return "androidx.annotation.CallSuper"
288                 "android.support.annotation.CheckResult",
289                 "android.annotation.CheckResult" -> return "androidx.annotation.CheckResult"
290                 "android.support.annotation.RequiresPermission",
291                 "android.annotation.RequiresPermission" -> return "androidx.annotation.RequiresPermission"
292                 "android.annotation.RequiresPermission.Read" -> return "androidx.annotation.RequiresPermission.Read"
293                 "android.annotation.RequiresPermission.Write" -> return "androidx.annotation.RequiresPermission.Write"
294 
295                 // These aren't support annotations, but could/should be:
296                 "android.annotation.CurrentTimeMillisLong",
297                 "android.annotation.DurationMillisLong",
298                 "android.annotation.ElapsedRealtimeLong",
299                 "android.annotation.UserIdInt",
300                 "android.annotation.BytesLong",
301 
302                 // These aren't support annotations
303                 "android.annotation.AppIdInt",
304                 "android.annotation.SuppressAutoDoc",
305                 "android.annotation.SystemApi",
306                 "android.annotation.TestApi",
307                 "android.annotation.CallbackExecutor",
308                 "android.annotation.Condemned",
309                 "android.annotation.Hide",
310 
311                 "android.annotation.Widget" -> {
312                     // Remove, unless (a) public or (b) specifically included in --showAnnotations
313                     return if (options.showAnnotations.matches(qualifiedName)) {
314                         qualifiedName
315                     } else if (filter != null) {
316                         val cls = codebase.findClass(qualifiedName)
317                         if (cls != null && filter.test(cls)) {
318                             qualifiedName
319                         } else {
320                             null
321                         }
322                     } else {
323                         qualifiedName
324                     }
325                 }
326 
327                 // Included for analysis, but should not be exported:
328                 "android.annotation.BroadcastBehavior",
329                 "android.annotation.SdkConstant",
330                 "android.annotation.RequiresFeature",
331                 "android.annotation.SystemService" -> return qualifiedName
332 
333                 // Should not be mapped to a different package name:
334                 "android.annotation.TargetApi",
335                 "android.annotation.SuppressLint" -> return qualifiedName
336 
337                 else -> {
338                     // Some new annotations added to the platform: assume they are support annotations?
339                     return when {
340                         // Special Kotlin annotations recognized by the compiler: map to supported package name
341                         qualifiedName.endsWith(".ParameterName") || qualifiedName.endsWith(".DefaultValue") ->
342                             "kotlin.annotations.jvm.internal${qualifiedName.substring(qualifiedName.lastIndexOf('.'))}"
343 
344                         // Other third party nullness annotations?
345                         isNullableAnnotation(qualifiedName) -> nullableAnnotationName(target)
346                         isNonNullAnnotation(qualifiedName) -> nonNullAnnotationName(target)
347 
348                         // Support library annotations are all included, as is the built-in stuff like @Retention
349                         qualifiedName.startsWith(ANDROIDX_ANNOTATION_PREFIX) -> return qualifiedName
350                         qualifiedName.startsWith(JAVA_LANG_PREFIX) -> return qualifiedName
351 
352                         // Unknown Android platform annotations
353                         qualifiedName.startsWith("android.annotation.") -> {
354                             // Remove, unless specifically included in --showAnnotations
355                             return if (options.showAnnotations.matches(qualifiedName)) {
356                                 qualifiedName
357                             } else {
358                                 null
359                             }
360                         }
361 
362                         qualifiedName.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX) -> {
363                             return mapName(
364                                 codebase,
365                                 ANDROIDX_ANNOTATION_PREFIX + qualifiedName.substring(ANDROID_SUPPORT_ANNOTATION_PREFIX.length),
366                                 filter,
367                                 target
368                             )
369                         }
370 
371                         else -> {
372                             // Remove, unless (a) public or (b) specifically included in --showAnnotations
373                             return if (options.showAnnotations.matches(qualifiedName)) {
374                                 qualifiedName
375                             } else if (filter != null) {
376                                 val cls = codebase.findClass(qualifiedName)
377                                 if (cls != null && filter.test(cls)) {
378                                     qualifiedName
379                                 } else {
380                                     null
381                                 }
382                             } else {
383                                 qualifiedName
384                             }
385                         }
386                     }
387                 }
388             }
389         }
390 
nullableAnnotationNamenull391         private fun nullableAnnotationName(target: AnnotationTarget) =
392             if (target == AnnotationTarget.SDK_STUBS_FILE) ANDROID_NULLABLE else ANDROIDX_NULLABLE
393 
394         private fun nonNullAnnotationName(target: AnnotationTarget) =
395             if (target == AnnotationTarget.SDK_STUBS_FILE) ANDROID_NONNULL else ANDROIDX_NONNULL
396 
397         /** The applicable targets for this annotation */
398         fun computeTargets(
399             annotation: AnnotationItem,
400             classFinder: (String) -> ClassItem?
401         ): Set<AnnotationTarget> {
402             val qualifiedName = annotation.qualifiedName() ?: return NO_ANNOTATION_TARGETS
403             if (options.passThroughAnnotations.contains(qualifiedName)) {
404                 return ANNOTATION_IN_ALL_STUBS
405             }
406             when (qualifiedName) {
407 
408                 // The typedef annotations are special: they should not be in the signature
409                 // files, but we want to include them in the external annotations file such that tools
410                 // can enforce them.
411                 "android.support.annotation.IntDef",
412                 "android.annotation.IntDef",
413                 "androidx.annotation.IntDef",
414                 "android.support.annotation.StringDef",
415                 "android.annotation.StringDef",
416                 "androidx.annotation.StringDef",
417                 "android.support.annotation.LongDef",
418                 "android.annotation.LongDef",
419                 "androidx.annotation.LongDef" -> return ANNOTATION_EXTERNAL_ONLY
420 
421                 // Not directly API relevant
422                 "android.view.ViewDebug.ExportedProperty",
423                 "android.view.ViewDebug.CapturedViewProperty" -> return ANNOTATION_STUBS_ONLY
424 
425                 // Skip known annotations that we (a) never want in external annotations and (b) we are
426                 // specially overwriting anyway in the stubs (and which are (c) not API significant)
427                 "java.lang.annotation.Native",
428                 "java.lang.SuppressWarnings",
429                 "java.lang.Override",
430                 "kotlin.Suppress",
431                 "androidx.annotation.experimental.UseExperimental",
432                 "kotlin.UseExperimental",
433                 "kotlin.OptIn" -> return NO_ANNOTATION_TARGETS
434 
435                 // TODO(aurimas): consider using annotation directly instead of modifiers
436                 "kotlin.Deprecated" -> return NO_ANNOTATION_TARGETS // tracked separately as a pseudo-modifier
437                 "java.lang.Deprecated", // tracked separately as a pseudo-modifier
438 
439                 // Below this when-statement we perform the correct lookup: check API predicate, and check
440                 // that retention is class or runtime, but we've hardcoded the answers here
441                 // for some common annotations.
442 
443                 "android.widget.RemoteViews.RemoteView",
444 
445                 "kotlin.annotation.Target",
446                 "kotlin.annotation.Retention",
447                 "kotlin.annotation.Repeatable",
448                 "kotlin.annotation.MustBeDocumented",
449                 "kotlin.DslMarker",
450                 "kotlin.PublishedApi",
451                 "kotlin.ExtensionFunctionType",
452 
453                 "java.lang.FunctionalInterface",
454                 "java.lang.SafeVarargs",
455                 "java.lang.annotation.Documented",
456                 "java.lang.annotation.Inherited",
457                 "java.lang.annotation.Repeatable",
458                 "java.lang.annotation.Retention",
459                 "java.lang.annotation.Target" -> return ANNOTATION_IN_ALL_STUBS
460 
461                 // Metalava already tracks all the methods that get generated due to these annotations.
462                 "kotlin.jvm.JvmOverloads",
463                 "kotlin.jvm.JvmField",
464                 "kotlin.jvm.JvmStatic",
465                 "kotlin.jvm.JvmName" -> return NO_ANNOTATION_TARGETS
466             }
467 
468             // @android.annotation.Nullable and NonNullable specially recognized annotations by the Kotlin
469             // compiler 1.3 and above: they always go in the stubs.
470             if (qualifiedName == ANDROID_NULLABLE ||
471                 qualifiedName == ANDROID_NONNULL ||
472                 qualifiedName == ANDROIDX_NULLABLE ||
473                 qualifiedName == ANDROIDX_NONNULL
474             ) {
475                 return ANNOTATION_IN_ALL_STUBS
476             }
477 
478             if (qualifiedName.startsWith("android.annotation.")) {
479                 // internal annotations not mapped to androidx: things like @SystemApi. Skip from
480                 // stubs, external annotations, signature files, etc.
481                 return NO_ANNOTATION_TARGETS
482             }
483 
484             // @RecentlyNullable and @RecentlyNonNull are specially recognized annotations by the Kotlin
485             // compiler: they always go in the stubs.
486             if (qualifiedName == RECENTLY_NULLABLE ||
487                 qualifiedName == RECENTLY_NONNULL
488             ) {
489                 return ANNOTATION_IN_ALL_STUBS
490             }
491 
492             // Determine the retention of the annotation: source retention annotations go
493             // in the external annotations file, class and runtime annotations go in
494             // the stubs files (except for the androidx annotations which are not included
495             // in the SDK and therefore cannot be referenced from it due to apt's unfortunate
496             // habit of loading all annotation classes it encounters.)
497 
498             if (qualifiedName.startsWith("androidx.annotation.")) {
499                 if (options.includeSourceRetentionAnnotations) {
500                     return ANNOTATION_IN_ALL_STUBS
501                 }
502 
503                 if (qualifiedName == ANDROIDX_NULLABLE || qualifiedName == ANDROIDX_NONNULL) {
504                     // Right now, nullness annotations (other than @RecentlyNullable and @RecentlyNonNull)
505                     // have to go in external annotations since they aren't in the class path for
506                     // annotation processors. However, we do want them showing up in the documentation using
507                     // their real annotation names.
508                     return ANNOTATION_IN_DOC_STUBS_AND_EXTERNAL
509                 }
510 
511                 return ANNOTATION_EXTERNAL
512             }
513 
514             // See if the annotation is pointing to an annotation class that is part of the API; if not, skip it.
515             val cls = classFinder(qualifiedName) ?: return NO_ANNOTATION_TARGETS
516             if (!ApiPredicate().test(cls)) {
517                 if (options.typedefMode != Options.TypedefMode.NONE) {
518                     if (cls.modifiers.annotations().any { it.isTypeDefAnnotation() }) {
519                         return ANNOTATION_SIGNATURE_ONLY
520                     }
521                 }
522 
523                 return NO_ANNOTATION_TARGETS
524             }
525 
526             if (cls.isAnnotationType()) {
527                 val retention = cls.getRetention()
528                 if (retention == AnnotationRetention.RUNTIME || retention == AnnotationRetention.CLASS) {
529                     return ANNOTATION_IN_ALL_STUBS
530                 }
531             }
532 
533             return ANNOTATION_EXTERNAL
534         }
535 
536         /**
537          * Given a "full" annotation name, shortens it by removing redundant package names.
538          * This is intended to be used by the [Compatibility.omitCommonPackages] flag
539          * to reduce clutter in signature files.
540          *
541          * For example, this method will convert `@androidx.annotation.Nullable` to just
542          * `@Nullable`, and `@androidx.annotation.IntRange(from=20)` to `IntRange(from=20)`.
543          */
shortenAnnotationnull544         fun shortenAnnotation(source: String): String {
545             return when {
546                 source == "@java.lang.Deprecated" -> "@Deprecated"
547                 source.startsWith("android.annotation.", 1) -> {
548                     "@" + source.substring("@android.annotation.".length)
549                 }
550                 source.startsWith(ANDROID_SUPPORT_ANNOTATION_PREFIX, 1) -> {
551                     "@" + source.substring("@android.support.annotation.".length)
552                 }
553                 source.startsWith(ANDROIDX_ANNOTATION_PREFIX, 1) -> {
554                     "@" + source.substring("@androidx.annotation.".length)
555                 }
556                 else -> source
557             }
558         }
559 
560         /**
561          * Reverses the [shortenAnnotation] method. Intended for use when reading in signature files
562          * that contain shortened type references.
563          */
unshortenAnnotationnull564         fun unshortenAnnotation(source: String): String {
565             return when {
566                 source == "@Deprecated" -> "@java.lang.Deprecated"
567                 // These 3 annotations are in the android.annotation. package, not android.support.annotation
568                 source.startsWith("@SystemService") ||
569                     source.startsWith("@TargetApi") ||
570                     source.startsWith("@SuppressLint") ->
571                     "@android.annotation." + source.substring(1)
572                 // If the first character of the name (after "@") is lower-case, then
573                 // assume it's a package name, so no need to shorten it.
574                 source.startsWith("@") && source[1].isLowerCase() -> source
575                 else -> {
576                     "@androidx.annotation." + source.substring(1)
577                 }
578             }
579         }
580 
581         /**
582          * If the given element has an *implicit* nullness, return it. This returns
583          * true for implicitly nullable elements, such as the parameter to the equals
584          * method, false for implicitly non null elements (such as annotation type
585          * members), and null if there is no implicit nullness.
586          */
getImplicitNullnessnull587         fun getImplicitNullness(item: Item): Boolean? {
588             var nullable: Boolean? = null
589 
590             // Is this a Kotlin object declaration (such as a companion object) ?
591             // If so, it is always non null.
592             val sourcePsi = item.psi()
593             if (sourcePsi is UElement && sourcePsi.sourcePsi is KtObjectDeclaration) {
594                 nullable = false
595             }
596 
597             // Constant field not initialized to null?
598             if (item is FieldItem &&
599                 (item.isEnumConstant() || item.modifiers.isFinal() && item.initialValue(false) != null)
600             ) {
601                 // Assigned to constant: not nullable
602                 nullable = false
603             } else if (item is FieldItem && item.modifiers.isFinal()) {
604                 // If we're looking at a final field, look at the right hand side
605                 // of the field to the field initialization. If that right hand side
606                 // for example represents a method call, and the method we're calling
607                 // is annotated with @NonNull, then the field (since it is final) will
608                 // always be @NonNull as well.
609                 val initializer = (item.psi() as? PsiField)?.initializer
610                 if (initializer != null && initializer is PsiReference) {
611                     val resolved = initializer.resolve()
612                     if (resolved is PsiModifierListOwner &&
613                         resolved.annotations.any {
614                             isNonNullAnnotation(it.qualifiedName ?: "")
615                         }
616                     ) {
617                         nullable = false
618                     }
619                 } else if (initializer != null && initializer is PsiCallExpression) {
620                     val resolved = initializer.resolveMethod()
621                     if (resolved != null &&
622                         resolved.annotations.any {
623                             isNonNullAnnotation(it.qualifiedName ?: "")
624                         }
625                     ) {
626                         nullable = false
627                     }
628                 }
629             } else if (item.synthetic && (item is MethodItem && item.isEnumSyntheticMethod() ||
630                     item is ParameterItem && item.containingMethod().isEnumSyntheticMethod())
631             ) {
632                 // Workaround the fact that the Kotlin synthetic enum methods
633                 // do not have nullness information
634                 nullable = false
635             }
636 
637             // Annotation type members cannot be null
638             if (item is MemberItem && item.containingClass().isAnnotationType()) {
639                 nullable = false
640             }
641 
642             // Equals and toString have known nullness
643             if (item is MethodItem && item.name() == "toString" && item.parameters().isEmpty()) {
644                 nullable = false
645             } else if (item is ParameterItem && item.containingMethod().name() == "equals" &&
646                 item.containingMethod().parameters().size == 1
647             ) {
648                 nullable = true
649             }
650 
651             return nullable
652         }
653     }
654 }
655 
656 /** Default implementation of an annotation item */
657 abstract class DefaultAnnotationItem(override val codebase: Codebase) : AnnotationItem {
658     protected var targets: Set<AnnotationTarget>? = null
659 
targetsnull660     override fun targets(): Set<AnnotationTarget> {
661         if (targets == null) {
662             targets = AnnotationItem.computeTargets(this) { className ->
663                 codebase.findClass(className)
664             }
665         }
666         return targets!!
667     }
668 }
669 
670 /** An attribute of an annotation, such as "value" */
671 interface AnnotationAttribute {
672     /** The name of the annotation */
673     val name: String
674     /** The annotation value */
675     val value: AnnotationAttributeValue
676 
677     /**
678      * Return all leaf values; this flattens the complication of handling
679      * {@code @SuppressLint("warning")} and {@code @SuppressLint({"warning1","warning2"})
680      */
leafValuesnull681     fun leafValues(): List<AnnotationAttributeValue> {
682         val result = mutableListOf<AnnotationAttributeValue>()
683         AnnotationAttributeValue.addValues(value, result)
684         return result
685     }
686 }
687 
688 /** An annotation value */
689 interface AnnotationAttributeValue {
690     /** Generates source code for this annotation value */
toSourcenull691     fun toSource(): String
692 
693     /** The value of the annotation */
694     fun value(): Any?
695 
696     /** If the annotation declaration references a field (or class etc), return the resolved class */
697     fun resolve(): Item?
698 
699     companion object {
700         fun addValues(value: AnnotationAttributeValue, into: MutableList<AnnotationAttributeValue>) {
701             if (value is AnnotationArrayAttributeValue) {
702                 for (v in value.values) {
703                     addValues(v, into)
704                 }
705             } else if (value is AnnotationSingleAttributeValue) {
706                 into.add(value)
707             }
708         }
709     }
710 }
711 
712 /** An annotation value (for a single item, not an array) */
713 interface AnnotationSingleAttributeValue : AnnotationAttributeValue {
714     /** The annotation value, expressed as source code */
715     val valueSource: String
716     /** The annotation value */
717     val value: Any?
718 
valuenull719     override fun value() = value
720 }
721 
722 /** An annotation value for an array of items */
723 interface AnnotationArrayAttributeValue : AnnotationAttributeValue {
724     /** The annotation values */
725     val values: List<AnnotationAttributeValue>
726 
727     override fun resolve(): Item? {
728         error("resolve() should not be called on an array value")
729     }
730 
731     override fun value() = values.mapNotNull { it.value() }.toTypedArray()
732 }
733 
734 class DefaultAnnotationAttribute(
735     override val name: String,
736     override val value: DefaultAnnotationValue
737 ) : AnnotationAttribute {
738     companion object {
createnull739         fun create(name: String, value: String): DefaultAnnotationAttribute {
740             return DefaultAnnotationAttribute(name, DefaultAnnotationValue.create(value))
741         }
742 
createListnull743         fun createList(source: String): List<AnnotationAttribute> {
744             val list = mutableListOf<AnnotationAttribute>() // TODO: default size = 2
745             var begin = 0
746             var index = 0
747             val length = source.length
748             while (index < length) {
749                 val c = source[index]
750                 if (c == '{') {
751                     index = findEnd(source, index + 1, length, '}')
752                 } else if (c == '"') {
753                     index = findEnd(source, index + 1, length, '"')
754                 } else if (c == ',') {
755                     addAttribute(list, source, begin, index)
756                     index++
757                     begin = index
758                     continue
759                 } else if (c == ' ' && index == begin) {
760                     begin++
761                 }
762 
763                 index++
764             }
765 
766             if (begin < length) {
767                 addAttribute(list, source, begin, length)
768             }
769 
770             return list
771         }
772 
findEndnull773         private fun findEnd(source: String, from: Int, to: Int, sentinel: Char): Int {
774             var i = from
775             while (i < to) {
776                 val c = source[i]
777                 if (c == '\\') {
778                     i++
779                 } else if (c == sentinel) {
780                     return i
781                 }
782                 i++
783             }
784             return to
785         }
786 
addAttributenull787         private fun addAttribute(list: MutableList<AnnotationAttribute>, source: String, from: Int, to: Int) {
788             var split = source.indexOf('=', from)
789             if (split >= to) {
790                 split = -1
791             }
792             val name: String
793             val value: String
794             val valueBegin: Int
795             val valueEnd: Int
796             if (split == -1) {
797                 valueBegin = split + 1
798                 valueEnd = to
799                 name = "value"
800             } else {
801                 name = source.substring(from, split).trim()
802                 valueBegin = split + 1
803                 valueEnd = to
804             }
805             value = source.substring(valueBegin, valueEnd).trim()
806             list.add(DefaultAnnotationAttribute.create(name, value))
807         }
808     }
809 
toStringnull810     override fun toString(): String {
811         return "DefaultAnnotationAttribute(name='$name', value=$value)"
812     }
813 }
814 
815 abstract class DefaultAnnotationValue : AnnotationAttributeValue {
816     companion object {
createnull817         fun create(value: String): DefaultAnnotationValue {
818             return if (value.startsWith("{")) { // Array
819                 DefaultAnnotationArrayAttributeValue(value)
820             } else {
821                 DefaultAnnotationSingleAttributeValue(value)
822             }
823         }
824     }
825 
toStringnull826     override fun toString(): String = toSource()
827 }
828 
829 class DefaultAnnotationSingleAttributeValue(override val valueSource: String) : DefaultAnnotationValue(),
830     AnnotationSingleAttributeValue {
831     @Suppress("IMPLICIT_CAST_TO_ANY")
832     override val value = when {
833         valueSource == SdkConstants.VALUE_TRUE -> true
834         valueSource == SdkConstants.VALUE_FALSE -> false
835         valueSource.startsWith("\"") -> valueSource.removeSurrounding("\"")
836         valueSource.startsWith('\'') -> valueSource.removeSurrounding("'")[0]
837         else -> try {
838             if (valueSource.contains(".")) {
839                 valueSource.toDouble()
840             } else {
841                 valueSource.toLong()
842             }
843         } catch (e: NumberFormatException) {
844             valueSource
845         }
846     }
847 
848     override fun resolve(): Item? = null
849 
850     override fun toSource() = valueSource
851 }
852 
853 class DefaultAnnotationArrayAttributeValue(val value: String) : DefaultAnnotationValue(),
854     AnnotationArrayAttributeValue {
855     init {
<lambda>null856         assert(value.startsWith("{") && value.endsWith("}")) { value }
857     }
858 
<lambda>null859     override val values = value.substring(1, value.length - 1).split(",").map {
860         DefaultAnnotationValue.create(it.trim())
861     }.toList()
862 
toSourcenull863     override fun toSource() = value
864 }
865