• 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.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