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