1 /* <lambda>null2 * Copyright (C) 2024 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.turbine 18 19 import com.android.tools.metalava.model.ClassTypeItem 20 import com.android.tools.metalava.model.PrimitiveTypeItem 21 import com.android.tools.metalava.model.ReferenceTypeItem 22 import com.android.tools.metalava.model.TypeArgumentTypeItem 23 import com.android.tools.metalava.model.TypeItem 24 import com.android.tools.metalava.model.TypeModifiers 25 import com.android.tools.metalava.model.TypeParameterScope 26 import com.android.tools.metalava.model.item.DefaultCodebase 27 import com.android.tools.metalava.model.type.ContextNullability 28 import com.android.tools.metalava.model.type.DefaultArrayTypeItem 29 import com.android.tools.metalava.model.type.DefaultClassTypeItem 30 import com.android.tools.metalava.model.type.DefaultPrimitiveTypeItem 31 import com.android.tools.metalava.model.type.DefaultTypeItemFactory 32 import com.android.tools.metalava.model.type.DefaultTypeModifiers 33 import com.android.tools.metalava.model.type.DefaultVariableTypeItem 34 import com.android.tools.metalava.model.type.DefaultWildcardTypeItem 35 import com.google.turbine.model.TurbineConstantTypeKind 36 import com.google.turbine.type.AnnoInfo 37 import com.google.turbine.type.Type 38 import javax.lang.model.element.Element 39 import javax.lang.model.element.TypeElement 40 import javax.lang.model.type.TypeKind 41 42 /** Creates [TypeItem]s from [Type]s. */ 43 internal class TurbineTypeItemFactory( 44 private val initializer: TurbineCodebaseInitialiser, 45 private val annotationFactory: TurbineAnnotationFactory, 46 typeParameterScope: TypeParameterScope, 47 ) : DefaultTypeItemFactory<Type, TurbineTypeItemFactory>(typeParameterScope) { 48 49 private val codebase: DefaultCodebase = initializer.codebase 50 51 override fun self() = this 52 53 override fun createNestedFactory(scope: TypeParameterScope) = 54 TurbineTypeItemFactory(initializer, annotationFactory, scope) 55 56 override fun getType( 57 underlyingType: Type, 58 contextNullability: ContextNullability, 59 isVarArg: Boolean, 60 ) = createType(underlyingType, isVarArg, contextNullability) 61 62 private fun createModifiers( 63 annos: List<AnnoInfo>, 64 contextNullability: ContextNullability, 65 ): TypeModifiers { 66 val typeAnnotations = annotationFactory.createAnnotations(annos) 67 // Compute the nullability, factoring in any context nullability and type annotations. 68 // Turbine does not support kotlin so the kotlin nullability is always null. 69 val nullability = contextNullability.compute(null, typeAnnotations) 70 return DefaultTypeModifiers.create(typeAnnotations, nullability) 71 } 72 73 internal fun createType( 74 type: Type, 75 isVarArg: Boolean, 76 contextNullability: ContextNullability = ContextNullability.none, 77 ): TypeItem { 78 return when (val kind = type.tyKind()) { 79 Type.TyKind.PRIM_TY -> { 80 type as Type.PrimTy 81 // Primitives are always non-null. 82 val modifiers = createModifiers(type.annos(), ContextNullability.forceNonNull) 83 when (type.primkind()) { 84 TurbineConstantTypeKind.BOOLEAN -> 85 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.BOOLEAN) 86 TurbineConstantTypeKind.BYTE -> 87 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.BYTE) 88 TurbineConstantTypeKind.CHAR -> 89 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.CHAR) 90 TurbineConstantTypeKind.DOUBLE -> 91 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.DOUBLE) 92 TurbineConstantTypeKind.FLOAT -> 93 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.FLOAT) 94 TurbineConstantTypeKind.INT -> 95 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.INT) 96 TurbineConstantTypeKind.LONG -> 97 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.LONG) 98 TurbineConstantTypeKind.SHORT -> 99 DefaultPrimitiveTypeItem(modifiers, PrimitiveTypeItem.Primitive.SHORT) 100 else -> 101 throw IllegalStateException("Invalid primitive type in API surface: $type") 102 } 103 } 104 Type.TyKind.ARRAY_TY -> { 105 createArrayType(type as Type.ArrayTy, isVarArg, contextNullability) 106 } 107 Type.TyKind.CLASS_TY -> { 108 type as Type.ClassTy 109 var outerClass: ClassTypeItem? = null 110 // A ClassTy is represented by list of SimpleClassTY each representing a nested 111 // class. e.g. , Outer.Inner.Inner1 will be represented by three simple classes 112 // Outer, Outer.Inner and Outer.Inner.Inner1 113 val iterator = type.classes().iterator() 114 while (iterator.hasNext()) { 115 val simpleClass = iterator.next() 116 117 // Select the ContextNullability. If there is another SimpleClassTy after this 118 // then this is an outer class which can never be null, so force it to be 119 // non-null. Otherwise, this is the nested class so use the supplied 120 // ContextNullability. 121 val actualContextNullability = 122 if (iterator.hasNext()) { 123 // For all outer class types, set the nullability to non-null. 124 ContextNullability.forceNonNull 125 } else { 126 // Use the supplied ContextNullability. 127 contextNullability 128 } 129 130 outerClass = 131 createNestedClassType(simpleClass, outerClass, actualContextNullability) 132 } 133 outerClass!! 134 } 135 Type.TyKind.TY_VAR -> { 136 type as Type.TyVar 137 val modifiers = createModifiers(type.annos(), contextNullability) 138 val typeParameter = typeParameterScope.getTypeParameter(type.sym().name()) 139 DefaultVariableTypeItem(modifiers, typeParameter) 140 } 141 Type.TyKind.WILD_TY -> { 142 type as Type.WildTy 143 // Wildcards themselves don't have a defined nullability. 144 val modifiers = 145 createModifiers(type.annotations(), ContextNullability.forceUndefined) 146 when (type.boundKind()) { 147 Type.WildTy.BoundKind.UPPER -> { 148 val upperBound = createWildcardBound(type.bound()) 149 DefaultWildcardTypeItem(modifiers, upperBound, null) 150 } 151 Type.WildTy.BoundKind.LOWER -> { 152 // LowerBounded types have java.lang.Object as upper bound 153 val upperBound = createWildcardBound(Type.ClassTy.OBJECT) 154 val lowerBound = createWildcardBound(type.bound()) 155 DefaultWildcardTypeItem(modifiers, upperBound, lowerBound) 156 } 157 Type.WildTy.BoundKind.NONE -> { 158 // Unbounded types have java.lang.Object as upper bound 159 val upperBound = createWildcardBound(Type.ClassTy.OBJECT) 160 DefaultWildcardTypeItem(modifiers, upperBound, null) 161 } 162 else -> 163 throw IllegalStateException("Invalid wildcard type in API surface: $type") 164 } 165 } 166 Type.TyKind.VOID_TY -> 167 DefaultPrimitiveTypeItem( 168 // Primitives are always non-null. 169 createModifiers(emptyList(), ContextNullability.forceNonNull), 170 PrimitiveTypeItem.Primitive.VOID 171 ) 172 Type.TyKind.NONE_TY -> 173 DefaultPrimitiveTypeItem( 174 // Primitives are always non-null. 175 DefaultTypeModifiers.emptyNonNullModifiers, 176 PrimitiveTypeItem.Primitive.VOID 177 ) 178 Type.TyKind.ERROR_TY -> { 179 // This is case of unresolved superclass or implemented interface 180 type as Type.ErrorTy 181 DefaultClassTypeItem( 182 codebase, 183 DefaultTypeModifiers.emptyUndefinedModifiers, 184 type.name(), 185 emptyList(), 186 null, 187 ) 188 } 189 else -> throw IllegalStateException("Invalid type in API surface: $kind") 190 } 191 } 192 193 private fun createWildcardBound(type: Type) = getGeneralType(type) as ReferenceTypeItem 194 195 private fun createArrayType( 196 type: Type.ArrayTy, 197 isVarArg: Boolean, 198 contextNullability: ContextNullability, 199 ): TypeItem { 200 // For Turbine's ArrayTy, due to a bug in Turbine, the annotations for multidimensional 201 // arrays are in the wrong order so this works around the issue. 202 203 // First, traverse from the outermost array to the innermost component type and add the 204 // [AnnoInfo]s to the list. Ending up with the innermost component type. Due to the bug the 205 // list contains [AnnoInfo]s from the innermost component type to the outermost types. 206 val annosList = mutableListOf<List<AnnoInfo>>() 207 var curr: Type = type 208 while (curr.tyKind() == Type.TyKind.ARRAY_TY) { 209 curr as Type.ArrayTy 210 annosList.add(curr.annos()) 211 curr = curr.elementType() 212 } 213 214 // Then, get the type for the innermost component, it has the correct annotations. Pass 215 // in the [ContextNullability.forComponentType] just in case this is the return type of an 216 // annotation method, or in other words the type of an annotation attribute. 217 val componentType = getType(curr, contextNullability.forComponentType()) 218 219 // Finally, traverse over the annotations from the innermost component type to the outermost 220 // array and construct a [DefaultArrayTypeItem] around the inner component type using its 221 // `List<AnnoInfo>`. The last `List<AnnoInfo>` is for the outermost array, and it needs to 222 // be tagged with the [isVarArg] value and [contextNullability]. 223 val lastIndex = annosList.size - 1 224 return annosList.foldIndexed(componentType) { index, typeItem, annos -> 225 val (arrayContextNullability, arrayVarArg) = 226 if (index == lastIndex) { 227 // Outermost array. Should be called with correct value of isVarArg and 228 // the contextual nullability. 229 Pair(contextNullability, isVarArg) 230 } else { 231 Pair(ContextNullability.none, false) 232 } 233 234 val modifiers = createModifiers(annos, arrayContextNullability) 235 DefaultArrayTypeItem(modifiers, typeItem, arrayVarArg) 236 } 237 } 238 239 /** 240 * Retrieves the `ClassTypeItem` representation of the outer class associated with a given 241 * nested class type. Intended for types that are not explicitly mentioned within the source 242 * code. 243 * 244 * @param type The `Type.ClassTy.SimpleClassTy` object representing the nested class. 245 * @return The `ClassTypeItem` representing the outer class. 246 */ 247 private fun getOuterClassType(type: Type.ClassTy.SimpleClassTy): ClassTypeItem { 248 val className = type.sym().qualifiedName 249 val classTypeElement = initializer.getTypeElement(className)!! 250 return createOuterClassType(classTypeElement.enclosingElement!!)!! 251 } 252 253 /** 254 * Constructs a `ClassTypeItem` representation from a type element. Intended for types that are 255 * not explicitly mentioned within the source code. 256 * 257 * @param element The `Element` object representing the type. 258 * @return The corresponding `ClassTypeItem`, or null if the `element` does not represent a 259 * declared type. 260 */ 261 private fun createOuterClassType(element: Element): ClassTypeItem? { 262 if (element.asType().kind != TypeKind.DECLARED) return null 263 264 val outerClassElement = element.enclosingElement!! 265 val outerClassTypeItem = createOuterClassType(outerClassElement) 266 267 element as TypeElement 268 269 // Since this type was never part of source , it won't have any annotation or arguments 270 val modifiers = DefaultTypeModifiers.emptyNonNullModifiers 271 val classTypeItem = 272 DefaultClassTypeItem( 273 codebase, 274 modifiers, 275 element.qualifiedName.toString(), // Assuming qualifiedName is available on element 276 emptyList(), 277 outerClassTypeItem 278 ) 279 return classTypeItem 280 } 281 282 private fun createNestedClassType( 283 type: Type.ClassTy.SimpleClassTy, 284 outerClass: ClassTypeItem?, 285 contextNullability: ContextNullability, 286 ): ClassTypeItem { 287 val sym = type.sym() 288 val outerClassItem = 289 if (sym.binaryName().contains("$") && outerClass == null) { 290 getOuterClassType(type) 291 } else { 292 outerClass 293 } 294 295 val modifiers = createModifiers(type.annos(), contextNullability) 296 val qualifiedName = sym.qualifiedName 297 val parameters = type.targs().map { getGeneralType(it) as TypeArgumentTypeItem } 298 return DefaultClassTypeItem(codebase, modifiers, qualifiedName, parameters, outerClassItem) 299 } 300 } 301