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