15d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis/*
24a360e3a3af230badc847867c117f605367170aaFilip Pavlis * Copyright 2017 The Android Open Source Project
35d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis *
45d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * Licensed under the Apache License, Version 2.0 (the "License");
55d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * you may not use this file except in compliance with the License.
65d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * You may obtain a copy of the License at
75d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis *
84a360e3a3af230badc847867c117f605367170aaFilip Pavlis *      http://www.apache.org/licenses/LICENSE-2.0
95d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis *
105d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * Unless required by applicable law or agreed to in writing, software
115d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * distributed under the License is distributed on an "AS IS" BASIS,
125d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * See the License for the specific language governing permissions and
144a360e3a3af230badc847867c117f605367170aaFilip Pavlis * limitations under the License.
155d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis */
165d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
17ba381a314edcd57963ed1ac5910595e04faf29ccFilip Pavlispackage com.android.tools.build.jetifier.processor.transform.proguard
185d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
19982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlisimport com.android.tools.build.jetifier.processor.cartesianProduct
20ba381a314edcd57963ed1ac5910595e04faf29ccFilip Pavlisimport com.android.tools.build.jetifier.processor.transform.proguard.patterns.GroupsReplacer
21ba381a314edcd57963ed1ac5910595e04faf29ccFilip Pavlisimport com.android.tools.build.jetifier.processor.transform.proguard.patterns.PatternHelper
225d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
235d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis/**
245d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * Parses and rewrites ProGuard rules that contain class specification. See ProGuard documentation
255d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis * https://www.guardsquare.com/en/proguard/manual/usage#classspecification
265d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis */
274a360e3a3af230badc847867c117f605367170aaFilip Pavlisclass ProGuardClassSpecParser(private val mapper: ProGuardTypesMapper) {
285d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
295d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    companion object {
305d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val RULES = "(keep[a-z]*|whyareyoukeeping|assumenosideeffects)"
315d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val RULES_MODIFIERS =
325d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            "(includedescriptorclasses|allowshrinking|allowoptimization|allowobfuscation)"
335d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
345d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val CLASS_NAME = "[\\w.$?*_%]+"
355d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val CLASS_MODIFIERS = "[!]?(public|final|abstract)"
365d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val CLASS_TYPES = "[!]?(interface|class|enum)"
375d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
385d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val ANNOTATION_TYPE = CLASS_NAME
395d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
405d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val FIELD_NAME = "[\\w?*_%]+"
415d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val FIELD_TYPE = CLASS_NAME
425d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val FIELD_MODIFIERS =
435d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            "[!]?(public|private|protected|static|volatile|transient)"
445d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
455d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val METHOD_MODIFIERS =
465d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            "[!]?(public|private|protected|static|synchronized|native|abstract|strictfp)"
475d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val RETURN_TYPE_NAME = CLASS_NAME
485d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val METHOD_NAME = "[\\w?*_]+"
495d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        private const val ARGS = "[^)]*"
505d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    }
515d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
525d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    val replacer = GroupsReplacer(
535d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        pattern = PatternHelper.build(
545d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            "-$RULES ($RULES_MODIFIERS )*(@⦅$ANNOTATION_TYPE⦆ )?($CLASS_MODIFIERS )*$CLASS_TYPES " +
555d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            "⦅$CLASS_NAME⦆( (extends|implements) ⦅$CLASS_NAME⦆)?+ *( *\\{⦅[^}]*⦆\\} *)?+"),
565d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        groupsMap = listOf(
574a360e3a3af230badc847867c117f605367170aaFilip Pavlis            { annotation: String -> mapper.replaceType(annotation) },
584a360e3a3af230badc847867c117f605367170aaFilip Pavlis            { className: String -> mapper.replaceType(className) },
594a360e3a3af230badc847867c117f605367170aaFilip Pavlis            { className2: String -> mapper.replaceType(className2) },
604a360e3a3af230badc847867c117f605367170aaFilip Pavlis            { bodyGroup: String -> rewriteBodyGroup(bodyGroup) }
615d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        )
625d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    )
635d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
645d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    private val bodyReplacers = listOf(
655d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] <fields>;
665d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
675d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            pattern = PatternHelper.build(
685d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($FIELD_MODIFIERS )*<fields> *$"),
695d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
704a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) }
715d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        )),
725d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
735d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] fieldType fieldName;
745d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
755d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            pattern = PatternHelper.build(
765d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($FIELD_MODIFIERS )*(⦅$FIELD_TYPE⦆ $FIELD_NAME) *$"),
775d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
784a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) },
794a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { fieldType: String -> mapper.replaceType(fieldType) }
805d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        )),
815d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
825d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] <methods>;
835d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
845d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            pattern = PatternHelper.build(
855d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($METHOD_MODIFIERS )*<methods> *$"),
865d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
874a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) }
885d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        )),
895d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
905d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] className(argumentType,...));
915d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
925d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            pattern = PatternHelper.build(
935d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($METHOD_MODIFIERS )*⦅$CLASS_NAME⦆ *\\(⦅$ARGS⦆\\) *$"),
945d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
954a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) },
964a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { className: String -> mapper.replaceType(className) },
974a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { argsType: String -> mapper.replaceMethodArgs(argsType) }
984a360e3a3af230badc847867c117f605367170aaFilip Pavlis        )),
995d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
1005d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] <init>(argumentType,...));
1015d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
1025d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            pattern = PatternHelper.build(
1035d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($METHOD_MODIFIERS )*<init> *\\(⦅$ARGS⦆\\) *$"),
1045d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
1054a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) },
1064a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { argsType: String -> mapper.replaceMethodArgs(argsType) }
1075d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        )),
1085d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
1095d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        // [@annotation] [[!]public|private|etc...] returnType methodName(argumentType,...));
1105d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        GroupsReplacer(
1114a360e3a3af230badc847867c117f605367170aaFilip Pavlis            pattern = PatternHelper.build(
1124a360e3a3af230badc847867c117f605367170aaFilip Pavlis                "^ *(@⦅$ANNOTATION_TYPE⦆ )?($METHOD_MODIFIERS )*" +
1135d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                "⦅$RETURN_TYPE_NAME⦆ $METHOD_NAME *\\(⦅$ARGS⦆\\) *$"),
1145d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            groupsMap = listOf(
1154a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { annotation: String -> mapper.replaceType(annotation) },
1164a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { returnType: String -> mapper.replaceType(returnType) },
1174a360e3a3af230badc847867c117f605367170aaFilip Pavlis                { argsType: String -> mapper.replaceMethodArgs(argsType) }
1185d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        ))
1195d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    )
1205d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
121982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis    private fun rewriteBodyGroup(bodyGroup: String): List<String> {
1225d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        if (bodyGroup == "*" || bodyGroup == "**") {
123982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis            return listOf(bodyGroup)
1245d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        }
1255d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis
1265d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis        return bodyGroup
1275d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            .split(';')
1285d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            .map {
1295d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                for (replacer in bodyReplacers) {
1305d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                    val matcher = replacer.pattern.matcher(it)
1315d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                    if (matcher.matches()) {
1325d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                        return@map replacer.runReplacements(matcher)
1335d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                    }
1345d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis                }
135982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis                return@map listOf(it)
1365d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis            }
137982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis            .cartesianProduct()
138982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis            .map { it.joinToString(separator = ";") }
139982679c45ee20f39c5da072ff6a80519ee262ef4Filip Pavlis            .toList()
1405d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis    }
1415d7619f3c22d5d40ff099ae5599bdbb47453d2ccFilip Pavlis}