• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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