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