1 /* 2 * Copyright (C) 2020 Square, Inc. 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 * https://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 package com.squareup.moshi.kotlin.codegen.api 17 18 import com.squareup.kotlinpoet.ClassName 19 20 /** 21 * Represents a proguard configuration for a given spec. This covers three main areas: 22 * - Keeping the target class name to Moshi's reflective lookup of the adapter. 23 * - Keeping the generated adapter class name + public constructor for reflective lookup. 24 * - Keeping any used JsonQualifier annotations and the properties they are attached to. 25 * - If the target class has default parameter values, also keeping the associated synthetic 26 * constructor as well as the DefaultConstructorMarker type Kotlin adds to it. 27 * 28 * Each rule is intended to be as specific and targeted as possible to reduce footprint, and each is 29 * conditioned on usage of the original target type. 30 * 31 * To keep this processor as an ISOLATING incremental processor, we generate one file per target 32 * class with a deterministic name (see [outputFilePathWithoutExtension]) with an appropriate 33 * originating element. 34 */ 35 @InternalMoshiCodegenApi 36 public data class ProguardConfig( 37 val targetClass: ClassName, 38 val adapterName: String, 39 val adapterConstructorParams: List<String>, 40 val targetConstructorHasDefaults: Boolean, 41 val targetConstructorParams: List<String>, 42 ) { outputFilePathWithoutExtensionnull43 public fun outputFilePathWithoutExtension(canonicalName: String): String { 44 return "META-INF/proguard/moshi-$canonicalName" 45 } 46 <lambda>null47 public fun writeTo(out: Appendable): Unit = out.run { 48 // 49 // -if class {the target class} 50 // -keepnames class {the target class} 51 // -if class {the target class} 52 // -keep class {the generated adapter} { 53 // <init>(...); 54 // private final {adapter fields} 55 // } 56 // 57 val targetName = targetClass.reflectionName() 58 val adapterCanonicalName = ClassName(targetClass.packageName, adapterName).canonicalName 59 // Keep the class name for Moshi's reflective lookup based on it 60 appendLine("-if class $targetName") 61 appendLine("-keepnames class $targetName") 62 63 appendLine("-if class $targetName") 64 appendLine("-keep class $adapterCanonicalName {") 65 // Keep the constructor for Moshi's reflective lookup 66 val constructorArgs = adapterConstructorParams.joinToString(",") 67 appendLine(" public <init>($constructorArgs);") 68 appendLine("}") 69 70 if (targetConstructorHasDefaults) { 71 // If the target class has default parameter values, keep its synthetic constructor 72 // 73 // -keepnames class kotlin.jvm.internal.DefaultConstructorMarker 74 // -keepclassmembers @com.squareup.moshi.JsonClass @kotlin.Metadata class * { 75 // synthetic <init>(...); 76 // } 77 // 78 appendLine("-if class $targetName") 79 appendLine("-keepnames class kotlin.jvm.internal.DefaultConstructorMarker") 80 appendLine("-if class $targetName") 81 appendLine("-keepclassmembers class $targetName {") 82 val allParams = targetConstructorParams.toMutableList() 83 val maskCount = if (targetConstructorParams.isEmpty()) { 84 0 85 } else { 86 (targetConstructorParams.size + 31) / 32 87 } 88 repeat(maskCount) { 89 allParams += "int" 90 } 91 allParams += "kotlin.jvm.internal.DefaultConstructorMarker" 92 val params = allParams.joinToString(",") 93 appendLine(" public synthetic <init>($params);") 94 appendLine("}") 95 } 96 } 97 } 98 99 /** 100 * Represents a qualified property with its [name] in the adapter fields and list of [qualifiers] 101 * associated with it. 102 */ 103 @InternalMoshiCodegenApi 104 public data class QualifierAdapterProperty(val name: String, val qualifiers: Set<ClassName>) 105