1 /* 2 * 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.ArrayTypeItem 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.ParameterItem 26 import com.android.tools.metalava.model.TypeItem 27 import com.android.tools.metalava.model.VisibilityLevel 28 import com.android.tools.metalava.model.visitors.ApiVisitor 29 import java.io.PrintWriter 30 import java.util.function.Predicate 31 32 class ProguardWriter( 33 private val writer: PrintWriter, 34 filterEmit: Predicate<Item>, 35 filterReference: Predicate<Item> 36 ) : 37 ApiVisitor( 38 visitConstructorsAsMethods = false, 39 nestInnerClasses = false, 40 inlineInheritedFields = true, 41 filterEmit = filterEmit, 42 filterReference = filterReference, 43 config = @Suppress("DEPRECATION") options.apiVisitorConfig, 44 ) { 45 visitClassnull46 override fun visitClass(cls: ClassItem) { 47 writer.print("-keep class ") 48 writer.print(cls.qualifiedNameWithDollarInnerClasses()) 49 writer.print(" {\n") 50 } 51 afterVisitClassnull52 override fun afterVisitClass(cls: ClassItem) { 53 writer.print("}\n") 54 } 55 visitConstructornull56 override fun visitConstructor(constructor: ConstructorItem) { 57 writer.print(" ") 58 writer.print("<init>") 59 60 writeParametersKeepList(constructor.parameters()) 61 writer.print(";\n") 62 } 63 visitMethodnull64 override fun visitMethod(method: MethodItem) { 65 writer.print(" ") 66 val modifiers = method.modifiers 67 val visibilityLevel = modifiers.getVisibilityLevel() 68 if (visibilityLevel != VisibilityLevel.PACKAGE_PRIVATE) { 69 writer.write(visibilityLevel.javaSourceCodeModifier + " ") 70 } 71 72 if (modifiers.isStatic()) { 73 writer.print("static ") 74 } 75 if (modifiers.isAbstract()) { 76 writer.print("abstract ") 77 } 78 if (modifiers.isSynchronized()) { 79 writer.print("synchronized ") 80 } 81 82 writer.print(getCleanTypeName(method.returnType())) 83 writer.print(" ") 84 writer.print(method.name()) 85 86 writeParametersKeepList(method.parameters()) 87 88 writer.print(";\n") 89 } 90 writeParametersKeepListnull91 private fun writeParametersKeepList(params: List<ParameterItem>) { 92 writer.print("(") 93 94 for (pi in params) { 95 if (pi !== params[0]) { 96 writer.print(", ") 97 } 98 writer.print(getCleanTypeName(pi.type())) 99 } 100 101 writer.print(")") 102 } 103 visitFieldnull104 override fun visitField(field: FieldItem) { 105 writer.print(" ") 106 107 val modifiers = field.modifiers 108 val visibilityLevel = modifiers.getVisibilityLevel() 109 if (visibilityLevel != VisibilityLevel.PACKAGE_PRIVATE) { 110 writer.write(visibilityLevel.javaSourceCodeModifier + " ") 111 } 112 113 if (modifiers.isStatic()) { 114 writer.print("static ") 115 } 116 if (modifiers.isTransient()) { 117 writer.print("transient ") 118 } 119 if (modifiers.isVolatile()) { 120 writer.print("volatile ") 121 } 122 123 writer.print(getCleanTypeName(field.type())) 124 125 writer.print(" ") 126 writer.print(field.name()) 127 128 writer.print(";\n") 129 } 130 getCleanTypeNamenull131 private fun getCleanTypeName(t: TypeItem?): String { 132 t ?: return "" 133 if (t is ArrayTypeItem) return getCleanTypeName(t.componentType) + "[]" 134 val cls = t.asClass() ?: return t.toCanonicalType() 135 return cls.qualifiedNameWithDollarInnerClasses() 136 } 137 } 138