1 /*
<lambda>null2  * Copyright (C) 2023 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 package com.android.hoststubgen.filters
17 
18 import com.android.hoststubgen.asm.ClassNodes
19 import com.android.hoststubgen.asm.toJvmClassName
20 
21 /**
22  * Filter to apply a policy to classes extending or implementing a class,
23  * either directly or indirectly.
24  *
25  * The policy won't apply to the super class itself.
26  */
27 class SubclassFilter(
28         private val classes: ClassNodes,
29         fallback: OutputFilter
30 ) : DelegatingFilter(fallback) {
31     private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf()
32 
33     /**
34      * Add a policy to all classes extending or implementing a class, either directly or indirectly.
35      */
36     fun addPolicy(superClassName: String, policy: FilterPolicyWithReason) {
37         mPolicies[superClassName.toJvmClassName()] = policy
38     }
39 
40     override fun getPolicyForClass(className: String): FilterPolicyWithReason {
41         return findPolicyForClass(className) ?: super.getPolicyForClass(className)
42     }
43 
44     /**
45      * Find a policy for a class.
46      */
47     private fun findPolicyForClass(className: String): FilterPolicyWithReason? {
48         val cn = classes.findClass(className) ?: return null
49 
50         if (cn.superName == null) {
51             return null
52         }
53         // First, check the direct super class / interfaces.
54         mPolicies[cn.superName]?.let { policy ->
55             return policy
56         }
57         cn.interfaces?.forEach { iface ->
58             mPolicies[iface]?.let { policy ->
59                 return policy
60             }
61         }
62 
63         // Then recurse.
64         cn.superName?.let { superName ->
65             findPolicyForClass(superName)?.let { policy ->
66                 return policy
67             }
68         }
69         cn.interfaces?.forEach { iface ->
70             findPolicyForClass(iface)?.let { policy ->
71                 return policy
72             }
73         }
74         return null
75     }
76 }