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 18 19 import com.android.tools.metalava.model.AnnotationTarget 20 import com.android.tools.metalava.model.ClassItem 21 import com.android.tools.metalava.model.ConstructorItem 22 import com.android.tools.metalava.model.FieldItem 23 import com.android.tools.metalava.model.Item 24 import com.android.tools.metalava.model.MethodItem 25 import com.android.tools.metalava.model.ModifierList 26 import com.android.tools.metalava.model.PackageItem 27 import com.android.tools.metalava.model.ParameterItem 28 import com.android.tools.metalava.model.PropertyItem 29 import com.android.tools.metalava.model.TypeItem 30 import com.android.tools.metalava.model.TypeParameterList 31 import com.android.tools.metalava.model.visitors.ApiVisitor 32 import java.io.PrintWriter 33 import java.util.function.Predicate 34 35 class SignatureWriter( 36 private val writer: PrintWriter, 37 filterEmit: Predicate<Item>, 38 filterReference: Predicate<Item>, 39 private val preFiltered: Boolean 40 ) : ApiVisitor( 41 visitConstructorsAsMethods = false, 42 nestInnerClasses = false, 43 inlineInheritedFields = true, 44 methodComparator = MethodItem.comparator, 45 fieldComparator = FieldItem.comparator, 46 filterEmit = filterEmit, 47 filterReference = filterReference, 48 showUnannotated = options.showUnannotated 49 ) { 50 override fun skip(item: Item): Boolean { 51 return super.skip(item) || item is ClassItem && item.notStrippable 52 } 53 54 init { 55 if (options.includeSignatureFormatVersion) { 56 writer.print(options.outputFormat.header()) 57 } 58 } 59 60 override fun visitPackage(pkg: PackageItem) { 61 writer.print("package ") 62 writeModifiers(pkg) 63 writer.print("${pkg.qualifiedName()} {\n\n") 64 } 65 66 override fun afterVisitPackage(pkg: PackageItem) { 67 writer.print("}\n\n") 68 } 69 70 override fun visitConstructor(constructor: ConstructorItem) { 71 writer.print(" ctor ") 72 writeModifiers(constructor) 73 // Note - we don't write out the type parameter list (constructor.typeParameterList()) in signature files! 74 // writeTypeParameterList(constructor.typeParameterList(), addSpace = true) 75 writer.print(constructor.containingClass().fullName()) 76 writeParameterList(constructor) 77 writeThrowsList(constructor) 78 writer.print(";\n") 79 } 80 81 override fun visitField(field: FieldItem) { 82 if (compatibility.skipInheritedConstants && field.inheritedField) { 83 return 84 } 85 86 val name = if (field.isEnumConstant()) "enum_constant" else "field" 87 writer.print(" ") 88 writer.print(name) 89 writer.print(" ") 90 writeModifiers(field) 91 writeType(field, field.type()) 92 writer.print(' ') 93 writer.print(field.name()) 94 field.writeValueWithSemicolon(writer, allowDefaultValue = false, requireInitialValue = false) 95 writer.print("\n") 96 } 97 98 override fun visitProperty(property: PropertyItem) { 99 writer.print(" property ") 100 writeModifiers(property) 101 writeType(property, property.type()) 102 writer.print(' ') 103 writer.print(property.name()) 104 writer.print(";\n") 105 } 106 107 override fun visitMethod(method: MethodItem) { 108 if (compatibility.skipAnnotationInstanceMethods && method.containingClass().isAnnotationType() && 109 !method.modifiers.isStatic() 110 ) { 111 return 112 } 113 114 if (compatibility.skipInheritedMethods && method.inheritedMethod) { 115 return 116 } 117 118 writer.print(" method ") 119 writeModifiers(method) 120 writeTypeParameterList(method.typeParameterList(), addSpace = true) 121 122 writeType(method, method.returnType()) 123 writer.print(' ') 124 writer.print(method.name()) 125 writeParameterList(method) 126 writeThrowsList(method) 127 128 if (compatibility.includeAnnotationDefaults) { 129 if (method.containingClass().isAnnotationType()) { 130 val default = method.defaultValue() 131 if (default.isNotEmpty()) { 132 writer.print(" default ") 133 writer.print(default) 134 } 135 } 136 } 137 138 writer.print(";\n") 139 } 140 141 override fun visitClass(cls: ClassItem) { 142 writer.print(" ") 143 144 writeModifiers(cls) 145 146 if (cls.isAnnotationType()) { 147 if (compatibility.classForAnnotations) { 148 // doclava incorrectly treats annotations (such as TargetApi) as an abstract class instead 149 // of an @interface! 150 // 151 // Example: 152 // public abstract class SuppressLint implements java.lang.annotation.Annotation { } 153 writer.print("class") 154 } else { 155 writer.print("@interface") 156 } 157 } else if (cls.isInterface()) { 158 writer.print("interface") 159 } else if (!compatibility.classForEnums && cls.isEnum()) { // compat mode calls enums "class" instead 160 writer.print("enum") 161 } else { 162 writer.print("class") 163 } 164 writer.print(" ") 165 writer.print(cls.fullName()) 166 writeTypeParameterList(cls.typeParameterList(), addSpace = false) 167 writeSuperClassStatement(cls) 168 writeInterfaceList(cls) 169 170 writer.print(" {\n") 171 } 172 173 override fun afterVisitClass(cls: ClassItem) { 174 writer.print(" }\n\n") 175 } 176 177 private fun writeModifiers(item: Item) { 178 ModifierList.write( 179 writer = writer, 180 modifiers = item.modifiers, 181 item = item, 182 target = AnnotationTarget.SIGNATURE_FILE, 183 includeDeprecated = true, 184 includeAnnotations = compatibility.annotationsInSignatures, 185 skipNullnessAnnotations = options.outputKotlinStyleNulls, 186 omitCommonPackages = compatibility.omitCommonPackages 187 ) 188 } 189 190 private fun writeSuperClassStatement(cls: ClassItem) { 191 if (!compatibility.classForEnums && cls.isEnum() || cls.isAnnotationType()) { 192 return 193 } 194 195 if (cls.isInterface() && compatibility.extendsForInterfaceSuperClass) { 196 // Written in the interface section instead 197 return 198 } 199 200 val superClass = if (preFiltered) 201 cls.superClassType() 202 else cls.filteredSuperClassType(filterReference) 203 if (superClass != null && !superClass.isJavaLangObject()) { 204 val superClassString = 205 superClass.toTypeString( 206 erased = compatibility.omitTypeParametersInInterfaces, 207 kotlinStyleNulls = false, 208 context = superClass.asClass(), 209 filter = filterReference 210 ) 211 writer.print(" extends ") 212 writer.print(superClassString) 213 } 214 } 215 216 private fun writeInterfaceList(cls: ClassItem) { 217 if (cls.isAnnotationType()) { 218 if (compatibility.classForAnnotations) { 219 writer.print(" implements java.lang.annotation.Annotation") 220 } 221 return 222 } 223 val isInterface = cls.isInterface() 224 225 val interfaces = if (preFiltered) 226 cls.interfaceTypes().asSequence() 227 else cls.filteredInterfaceTypes(filterReference).asSequence() 228 val all: Sequence<TypeItem> = if (isInterface && compatibility.extendsForInterfaceSuperClass) { 229 val superClassType = cls.superClassType() 230 if (superClassType != null && !superClassType.isJavaLangObject()) { 231 interfaces.plus(sequenceOf(superClassType)) 232 } else { 233 interfaces 234 } 235 } else { 236 interfaces 237 } 238 239 if (all.any()) { 240 val label = 241 if (isInterface && !compatibility.extendsForInterfaceSuperClass) { 242 val superInterface = cls.filteredSuperclass(filterReference) 243 if (superInterface != null && !superInterface.isJavaLangObject()) { 244 // For interfaces we've already listed "extends <super interface>"; we don't 245 // want to repeat "extends " here 246 "" 247 } else { 248 " extends" 249 } 250 } else { 251 " implements" 252 } 253 writer.print(label) 254 all.sortedWith(TypeItem.comparator).forEach { item -> 255 writer.print(" ") 256 writer.print( 257 item.toTypeString( 258 erased = compatibility.omitTypeParametersInInterfaces, 259 kotlinStyleNulls = false, 260 context = item.asClass(), 261 filter = filterReference 262 ) 263 ) 264 } 265 } 266 } 267 268 private fun writeTypeParameterList(typeList: TypeParameterList, addSpace: Boolean) { 269 val typeListString = typeList.toString() 270 if (typeListString.isNotEmpty()) { 271 writer.print(typeListString) 272 if (addSpace) { 273 writer.print(' ') 274 } 275 } 276 } 277 278 private fun writeParameterList(method: MethodItem) { 279 writer.print("(") 280 val emitParameterNames = compatibility.parameterNames 281 method.parameters().asSequence().forEachIndexed { i, parameter -> 282 if (i > 0) { 283 writer.print(", ") 284 } 285 writeModifiers(parameter) 286 writeType(parameter, parameter.type()) 287 if (emitParameterNames) { 288 val name = parameter.publicName() 289 if (name != null) { 290 writer.print(" ") 291 writer.print(name) 292 } 293 } 294 if (options.outputDefaultValues && parameter.hasDefaultValue()) { 295 writer.print(" = ") 296 val defaultValue = parameter.defaultValue() 297 if (defaultValue != null) { 298 writer.print(defaultValue) 299 } else { 300 // null is a valid default value! 301 writer.print("null") 302 } 303 } 304 } 305 writer.print(")") 306 } 307 308 private fun writeType( 309 item: Item, 310 type: TypeItem?, 311 outputKotlinStyleNulls: Boolean = options.outputKotlinStyleNulls 312 ) { 313 type ?: return 314 315 var typeString = type.toTypeString( 316 outerAnnotations = false, 317 innerAnnotations = compatibility.annotationsInSignatures, 318 erased = false, 319 kotlinStyleNulls = outputKotlinStyleNulls, 320 context = item, 321 filter = filterReference 322 ) 323 324 // Strip java.lang. prefix? 325 if (compatibility.omitCommonPackages) { 326 typeString = TypeItem.shortenTypes(typeString) 327 } 328 329 if (compatibility.includeExtendsObjectInWildcard && typeString.endsWith(", ?>") && item is ParameterItem) { 330 // This wasn't done universally; just in a few places, so replicate it for those exact places 331 val methodName = item.containingMethod().name() 332 when (methodName) { 333 "computeIfAbsent" -> { 334 if (typeString == "java.util.function.Function<? super java.lang.Object, ?>") { 335 typeString = "java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>" 336 } 337 } 338 "computeIfPresent", "merge", "replaceAll", "compute" -> { 339 if (typeString == "java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ?>") { 340 typeString = 341 "java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>" 342 } 343 } 344 } 345 } 346 347 writer.print(typeString) 348 } 349 350 private fun writeThrowsList(method: MethodItem) { 351 val throws = when { 352 preFiltered -> method.throwsTypes().asSequence() 353 compatibility.filterThrowsClasses -> method.filteredThrowsTypes(filterReference).asSequence() 354 else -> method.throwsTypes().asSequence() 355 } 356 if (throws.any()) { 357 writer.print(" throws ") 358 throws.asSequence().sortedWith(ClassItem.fullNameComparator).forEachIndexed { i, type -> 359 if (i > 0) { 360 writer.print(", ") 361 } 362 writer.print(type.qualifiedName()) 363 } 364 } 365 } 366 }