1 /* 2 * Copyright 2018 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.build.jetifier.core.rule 18 19 import com.android.tools.build.jetifier.core.proguard.ProGuardType 20 import com.android.tools.build.jetifier.core.type.JavaType 21 import com.google.gson.annotations.SerializedName 22 import java.util.regex.Pattern 23 24 /** 25 * Rule that rewrites a Java type based on the given arguments. 26 * 27 * Used in the preprocessor when generating [TypesMap]. 28 * 29 * @param from Regular expression where packages are separated via '/' and inner class separator 30 * is "$". Used to match the input type. 31 * @param to A string to be used as a replacement if the 'from' pattern is matched. It can also 32 * apply groups matched from the original pattern using {x} annotation, e.g. {0}. 33 */ 34 class RewriteRule(private val from: String, private val to: String) { 35 36 companion object { 37 const val IGNORE_RUNTIME = "ignore" 38 const val IGNORE_PREPROCESSOR_ONLY = "ignoreInPreprocessorOnly" 39 } 40 41 // We escape '$' so we don't conflict with regular expression symbols. 42 private val inputPattern = Pattern.compile("^${from.replace("$", "\\$")}$") 43 private val outputPattern = to.replace("$", "\$") 44 45 /* 46 * Whether this is any type of an ignore rule. 47 */ isIgnoreRulenull48 fun isIgnoreRule() = isRuntimeIgnoreRule() || isPreprocessorOnlyIgnoreRule() 49 50 /* 51 * Whether this rules is an ignore rule. 52 * 53 * Any type matched to [from] will be in such case ignored by the preprocessor (thus missing 54 * from the map) but it will be also ignored during rewriting. 55 */ 56 fun isRuntimeIgnoreRule() = to == IGNORE_RUNTIME 57 58 /* 59 * Whether this rule is an ignore rule that should be used only in the preprocessor. 60 * 61 * That means that error is still thrown if [from] is found in a library that is being 62 * rewritten. Use this for types that are internal to support library. This is weaker version of 63 * [isRuntimeIgnoreRule]. 64 */ 65 fun isPreprocessorOnlyIgnoreRule() = to == IGNORE_PREPROCESSOR_ONLY 66 67 /** 68 * Rewrites the given java type. Returns null if this rule is not applicable for the given type. 69 */ 70 fun apply(input: JavaType): TypeRewriteResult { 71 val matcher = inputPattern.matcher(input.fullName) 72 if (!matcher.matches()) { 73 return TypeRewriteResult.NOT_APPLIED 74 } 75 76 if (isIgnoreRule()) { 77 return TypeRewriteResult.IGNORED 78 } 79 80 var result = outputPattern 81 for (i in 0 until matcher.groupCount()) { 82 result = result.replace("{$i}", matcher.group(i + 1)) 83 } 84 85 return TypeRewriteResult(JavaType(result)) 86 } 87 reversenull88 fun reverse(): RewriteRule { 89 val newFrom = to.replace("{0}", "(.*)") 90 val newTo = from.replace("(.*)", "{0}") 91 return RewriteRule(newFrom, newTo) 92 } 93 94 /* 95 * Returns whether this rule is an ignore rule and applies to the given proGuard type. 96 */ doesThisIgnoreProGuardnull97 fun doesThisIgnoreProGuard(type: ProGuardType): Boolean { 98 if (!isIgnoreRule()) { 99 return false 100 } 101 102 val matcher = inputPattern.matcher(type.value) 103 return matcher.matches() 104 } 105 toStringnull106 override fun toString(): String { 107 return "$inputPattern -> $outputPattern " 108 } 109 110 /** Returns JSON data model of this class */ toJsonnull111 fun toJson(): JsonData { 112 return JsonData(from, to) 113 } 114 115 /** 116 * JSON data model for [RewriteRule]. 117 */ 118 data class JsonData( 119 @SerializedName("from") 120 val from: String, 121 122 @SerializedName("to") 123 val to: String) { 124 125 /** Creates instance of [RewriteRule] */ toRulenull126 fun toRule(): RewriteRule { 127 return RewriteRule(from, to) 128 } 129 } 130 131 /** 132 * Result of java type rewrite using [RewriteRule] 133 */ 134 data class TypeRewriteResult(val result: JavaType?, val isIgnored: Boolean = false) { 135 136 companion object { 137 val NOT_APPLIED = TypeRewriteResult(result = null, isIgnored = false) 138 139 val IGNORED = TypeRewriteResult(result = null, isIgnored = true) 140 } 141 } 142 }