Implement TurbineAnnotationItem

This CL aims to make the test `test annotations` pass for Turbine

Bug: 308386397
Test: ./gradlew
Change-Id: If0d2a3e1ac4804e936f3469baaf106207035a7d3
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineAnnotationItem.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineAnnotationItem.kt
new file mode 100644
index 0000000..365ae1f
--- /dev/null
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineAnnotationItem.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava.model.turbine
+
+import com.android.tools.metalava.model.AnnotationAttribute
+import com.android.tools.metalava.model.DefaultAnnotationItem
+
+class TurbineAnnotationItem
+constructor(
+    override val codebase: TurbineBasedCodebase,
+    originalName: String?,
+    val annotationAttribute: List<AnnotationAttribute>,
+) : DefaultAnnotationItem(codebase, originalName, { annotationAttribute }) {}
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
index 98b4cfe..a140600 100644
--- a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
@@ -16,6 +16,12 @@
 
 package com.android.tools.metalava.model.turbine
 
+import com.android.tools.metalava.model.AnnotationAttribute
+import com.android.tools.metalava.model.AnnotationAttributeValue
+import com.android.tools.metalava.model.AnnotationItem
+import com.android.tools.metalava.model.DefaultAnnotationArrayAttributeValue
+import com.android.tools.metalava.model.DefaultAnnotationAttribute
+import com.android.tools.metalava.model.DefaultAnnotationSingleAttributeValue
 import com.google.common.collect.ImmutableList
 import com.google.common.collect.ImmutableMap
 import com.google.turbine.binder.Binder
@@ -23,13 +29,19 @@
 import com.google.turbine.binder.ClassPathBinder
 import com.google.turbine.binder.Processing.ProcessorInfo
 import com.google.turbine.binder.bound.SourceTypeBoundClass
+import com.google.turbine.binder.bound.TurbineClassValue
 import com.google.turbine.binder.bound.TypeBoundClass
 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo
 import com.google.turbine.binder.bytecode.BytecodeBoundClass
 import com.google.turbine.binder.env.CompoundEnv
 import com.google.turbine.binder.sym.ClassSymbol
 import com.google.turbine.diag.TurbineLog
+import com.google.turbine.model.Const
+import com.google.turbine.model.Const.ArrayInitValue
+import com.google.turbine.model.Const.Kind
+import com.google.turbine.model.Const.Value
 import com.google.turbine.tree.Tree.CompUnit
+import com.google.turbine.type.AnnoInfo
 import java.io.File
 import java.util.Optional
 import javax.lang.model.SourceVersion
@@ -121,7 +133,7 @@
         if (pkgItem != null) {
             return pkgItem as TurbinePackageItem
         } else {
-            val modifers = TurbineModifierItem.create(codebase, 0)
+            val modifers = TurbineModifierItem.create(codebase, 0, null)
             val turbinePkgItem = TurbinePackageItem.create(codebase, name, modifers)
             codebase.addPackage(turbinePkgItem)
             return turbinePkgItem
@@ -167,7 +179,8 @@
         val qualifiedName = sym.binaryName().replace('/', '.').replace('$', '.')
         val simpleName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1)
         val fullName = sym.simpleName().replace('$', '.')
-        val modifierItem = TurbineModifierItem.create(codebase, cls.access())
+        val annotations = createAnnotations(cls.annotations()).toMutableList()
+        val modifierItem = TurbineModifierItem.create(codebase, cls.access(), annotations)
         val classItem =
             TurbineClassItem(
                 codebase,
@@ -222,7 +235,9 @@
     private fun createFields(classItem: TurbineClassItem, fields: ImmutableList<FieldInfo>) {
         classItem.fields =
             fields.map { field ->
-                val fieldModifierItem = TurbineModifierItem.create(codebase, field.access())
+                val annotations = createAnnotations(field.annotations()).toMutableList()
+                val fieldModifierItem =
+                    TurbineModifierItem.create(codebase, field.access(), annotations)
                 TurbineFieldItem(
                     codebase,
                     field.name(),
@@ -231,4 +246,57 @@
                 )
             }
     }
+
+    /** Creates a list of AnnotationItems from given list of Turbine Annotations */
+    private fun createAnnotations(annotations: List<AnnoInfo>): List<AnnotationItem> {
+        return annotations.map { createAnnotation(it) }
+    }
+
+    private fun createAnnotation(annotation: AnnoInfo): TurbineAnnotationItem {
+        val annoAttrs = getAnnotationAttributes(annotation.values())
+        val nameList = annotation.tree().name().map { it.value() }
+        val simpleName = nameList.joinToString(separator = ".")
+        val clsSym = annotation.sym()
+        val qualifiedName =
+            if (clsSym == null) simpleName
+            else clsSym.binaryName().replace('/', '.').replace('$', '.')
+        return TurbineAnnotationItem(codebase, qualifiedName, annoAttrs)
+    }
+
+    /** Creates a list of AnnotationAttribute from the map of name-value attribute pairs */
+    private fun getAnnotationAttributes(
+        attrs: ImmutableMap<String, Const>
+    ): List<AnnotationAttribute> {
+        val attributes = mutableListOf<AnnotationAttribute>()
+        for ((name, value) in attrs) {
+            attributes.add(DefaultAnnotationAttribute(name, createAttrValue(value)))
+        }
+        return attributes
+    }
+
+    private fun createAttrValue(const: Const): AnnotationAttributeValue {
+        if (const.kind() == Kind.ARRAY) {
+            val arrayVal = const as ArrayInitValue
+            return DefaultAnnotationArrayAttributeValue(
+                { arrayVal.toString() },
+                { arrayVal.elements().map { createAttrValue(it) } }
+            )
+        }
+        return DefaultAnnotationSingleAttributeValue({ const.toString() }, { getValue(const) })
+    }
+
+    private fun getValue(const: Const): Any? {
+        when (const.kind()) {
+            Kind.PRIMITIVE -> {
+                val value = const as Value
+                return value.getValue()
+            }
+            // For cases like AnyClass.class, return the qualified name of AnyClass
+            Kind.CLASS_LITERAL -> {
+                val value = const as TurbineClassValue
+                return value.type().toString()
+            }
+            else -> return const.toString()
+        }
+    }
 }
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineModifierItem.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineModifierItem.kt
index f4cdda8..880ed38 100644
--- a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineModifierItem.kt
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineModifierItem.kt
@@ -26,18 +26,22 @@
 internal constructor(
     codebase: Codebase,
     flags: Int = PACKAGE_PRIVATE,
-    annotations: MutableList<AnnotationItem>? = null,
-) : DefaultModifierList(codebase, flags, annotations), ModifierList, MutableModifierList {
+    annotations: List<AnnotationItem>?
+) :
+    DefaultModifierList(codebase, flags, annotations?.toMutableList()),
+    ModifierList,
+    MutableModifierList {
     companion object {
         fun create(
             codebase: Codebase,
             flag: Int,
+            annotations: List<AnnotationItem>?
         ): TurbineModifierItem {
             if (flag == 0) {
                 // No Modifier. Default modifier is PACKAGE_PRIVATE in such case
-                return TurbineModifierItem(codebase)
+                return TurbineModifierItem(codebase, annotations = annotations)
             }
-            return TurbineModifierItem(codebase, computeFlag(flag))
+            return TurbineModifierItem(codebase, computeFlag(flag), annotations)
         }
 
         /**
diff --git a/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt b/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
index f8b0fd7..daca2a3 100644
--- a/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
+++ b/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
@@ -1,7 +1,6 @@
 com.android.tools.metalava.model.testsuite.BootstrapSourceModelProviderTest
   060 - check method exists[turbine,java]
   070 - check constructor exists[turbine,java]
-  130 - test annotations[turbine,java]
 
 com.android.tools.metalava.model.testsuite.CommonClassItemTest
   Find method with type parameterized by two types[turbine,java]
@@ -12,14 +11,6 @@
   MethodItem superMethods() on simple method[turbine,java]
   MethodItem type[turbine,java]
 
-com.android.tools.metalava.model.testsuite.annotationitem.CommonAnnotationItemTest
-  annotation with annotation values[turbine,java]
-  annotation with boolean values[turbine,java]
-  annotation with char values[turbine,java]
-  annotation with class values[turbine,java]
-  annotation with number values[turbine,java]
-  annotation with string values[turbine,java]
-
 com.android.tools.metalava.model.testsuite.typeitem.CommonTypeItemTest
   Test class array types[turbine,java]
   Test class types[turbine,java]