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