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.PropertyItem 28 import com.android.tools.metalava.model.TypeItem 29 import com.android.tools.metalava.model.TypeParameterList 30 import com.android.tools.metalava.model.visitors.ApiVisitor 31 import java.io.PrintWriter 32 import java.util.function.Predicate 33 34 class SignatureWriter( 35 private val writer: PrintWriter, 36 filterEmit: Predicate<Item>, 37 filterReference: Predicate<Item>, 38 private val preFiltered: Boolean, 39 var emitHeader: EmitFileHeader = options.includeSignatureFormatVersionNonRemoved 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 (emitHeader == EmitFileHeader.ALWAYS) { 52 writer.print(options.outputFormat.header()) 53 emitHeader = EmitFileHeader.NEVER 54 } 55 } 56 57 fun write(text: String) { 58 if (emitHeader == EmitFileHeader.IF_NONEMPTY_FILE) { 59 if (options.includeSignatureFormatVersion) { 60 writer.print(options.outputFormat.header()) 61 } 62 emitHeader = EmitFileHeader.NEVER 63 } 64 writer.print(text) 65 } 66 67 override fun visitPackage(pkg: PackageItem) { 68 write("package ") 69 writeModifiers(pkg) 70 write("${pkg.qualifiedName()} {\n\n") 71 } 72 73 override fun afterVisitPackage(pkg: PackageItem) { 74 write("}\n\n") 75 } 76 77 override fun visitConstructor(constructor: ConstructorItem) { 78 write(" ctor ") 79 writeModifiers(constructor) 80 writeTypeParameterList(constructor.typeParameterList(), addSpace = true) 81 write(constructor.containingClass().fullName()) 82 writeParameterList(constructor) 83 writeThrowsList(constructor) 84 write(";\n") 85 } 86 87 override fun visitField(field: FieldItem) { 88 val name = if (field.isEnumConstant()) "enum_constant" else "field" 89 write(" ") 90 write(name) 91 write(" ") 92 writeModifiers(field) 93 writeType(field, field.type()) 94 write(" ") 95 write(field.name()) 96 field.writeValueWithSemicolon(writer, allowDefaultValue = false, requireInitialValue = false) 97 write("\n") 98 } 99 100 override fun visitProperty(property: PropertyItem) { 101 write(" property ") 102 writeModifiers(property) 103 writeType(property, property.type()) 104 write(" ") 105 write(property.name()) 106 write(";\n") 107 } 108 109 override fun visitMethod(method: MethodItem) { 110 write(" method ") 111 writeModifiers(method) 112 writeTypeParameterList(method.typeParameterList(), addSpace = true) 113 114 writeType(method, method.returnType()) 115 write(" ") 116 write(method.name()) 117 writeParameterList(method) 118 writeThrowsList(method) 119 120 if (method.containingClass().isAnnotationType()) { 121 val default = method.defaultValue() 122 if (default.isNotEmpty()) { 123 write(" default ") 124 write(default) 125 } 126 } 127 128 write(";\n") 129 } 130 131 override fun visitClass(cls: ClassItem) { 132 write(" ") 133 134 writeModifiers(cls) 135 136 if (cls.isAnnotationType()) { 137 write("@interface") 138 } else if (cls.isInterface()) { 139 write("interface") 140 } else if (cls.isEnum()) { 141 write("enum") 142 } else { 143 write("class") 144 } 145 write(" ") 146 write(cls.fullName()) 147 writeTypeParameterList(cls.typeParameterList(), addSpace = false) 148 writeSuperClassStatement(cls) 149 writeInterfaceList(cls) 150 151 write(" {\n") 152 } 153 154 override fun afterVisitClass(cls: ClassItem) { 155 write(" }\n\n") 156 } 157 158 private fun writeModifiers(item: Item) { 159 ModifierList.write( 160 writer = writer, 161 modifiers = item.modifiers, 162 item = item, 163 target = AnnotationTarget.SIGNATURE_FILE, 164 includeDeprecated = true, 165 skipNullnessAnnotations = options.outputKotlinStyleNulls, 166 omitCommonPackages = true 167 ) 168 } 169 170 private fun writeSuperClassStatement(cls: ClassItem) { 171 if (cls.isEnum() || cls.isAnnotationType()) { 172 return 173 } 174 175 val superClass = if (preFiltered) 176 cls.superClassType() 177 else cls.filteredSuperClassType(filterReference) 178 if (superClass != null && !superClass.isJavaLangObject()) { 179 val superClassString = 180 superClass.toTypeString( 181 kotlinStyleNulls = false, 182 context = superClass.asClass(), 183 filter = filterReference 184 ) 185 write(" extends ") 186 write(superClassString) 187 } 188 } 189 190 private fun writeInterfaceList(cls: ClassItem) { 191 if (cls.isAnnotationType()) { 192 return 193 } 194 val isInterface = cls.isInterface() 195 196 val interfaces = if (preFiltered) 197 cls.interfaceTypes().asSequence() 198 else cls.filteredInterfaceTypes(filterReference).asSequence() 199 200 if (interfaces.any()) { 201 val label = 202 if (isInterface) { 203 val superInterface = cls.filteredSuperclass(filterReference) 204 if (superInterface != null && !superInterface.isJavaLangObject()) { 205 // For interfaces we've already listed "extends <super interface>"; we don't 206 // want to repeat "extends " here 207 "" 208 } else { 209 " extends" 210 } 211 } else { 212 " implements" 213 } 214 write(label) 215 interfaces.sortedWith(TypeItem.comparator).forEach { item -> 216 write(" ") 217 write( 218 item.toTypeString( 219 kotlinStyleNulls = false, 220 context = item.asClass(), 221 filter = filterReference 222 ) 223 ) 224 } 225 } 226 } 227 228 private fun writeTypeParameterList(typeList: TypeParameterList, addSpace: Boolean) { 229 val typeListString = typeList.toString() 230 if (typeListString.isNotEmpty()) { 231 write(typeListString) 232 if (addSpace) { 233 write(" ") 234 } 235 } 236 } 237 238 private fun writeParameterList(method: MethodItem) { 239 write("(") 240 method.parameters().asSequence().forEachIndexed { i, parameter -> 241 if (i > 0) { 242 write(", ") 243 } 244 if (parameter.hasDefaultValue() && 245 options.outputDefaultValues && 246 options.outputFormat.conciseDefaultValues 247 ) { 248 // Concise representation of a parameter with a default 249 write("optional ") 250 } 251 writeModifiers(parameter) 252 writeType(parameter, parameter.type()) 253 val name = parameter.publicName() 254 if (name != null) { 255 write(" ") 256 write(name) 257 } 258 if (parameter.isDefaultValueKnown() && 259 options.outputDefaultValues && 260 !options.outputFormat.conciseDefaultValues 261 ) { 262 write(" = ") 263 val defaultValue = parameter.defaultValue() 264 if (defaultValue != null) { 265 write(defaultValue) 266 } else { 267 // null is a valid default value! 268 write("null") 269 } 270 } 271 } 272 write(")") 273 } 274 275 private fun writeType( 276 item: Item, 277 type: TypeItem?, 278 outputKotlinStyleNulls: Boolean = options.outputKotlinStyleNulls 279 ) { 280 type ?: return 281 282 var typeString = type.toTypeString( 283 outerAnnotations = false, 284 innerAnnotations = true, 285 erased = false, 286 kotlinStyleNulls = outputKotlinStyleNulls, 287 context = item, 288 filter = filterReference 289 ) 290 291 // Strip java.lang. prefix 292 typeString = TypeItem.shortenTypes(typeString) 293 294 write(typeString) 295 } 296 297 private fun writeThrowsList(method: MethodItem) { 298 val throws = when { 299 preFiltered -> method.throwsTypes().asSequence() 300 else -> method.filteredThrowsTypes(filterReference).asSequence() 301 } 302 if (throws.any()) { 303 write(" throws ") 304 throws.asSequence().sortedWith(ClassItem.fullNameComparator).forEachIndexed { i, type -> 305 if (i > 0) { 306 write(", ") 307 } 308 write(type.qualifiedName()) 309 } 310 } 311 } 312 } 313 314 enum class EmitFileHeader { 315 ALWAYS, 316 NEVER, 317 IF_NONEMPTY_FILE 318 } 319