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.getDirectOuterClassName 20 21 /** 22 * This is used as the second last fallback filter. This filter propagates the class-wide policy 23 * (obtained from [outermostFilter]) to the fields and methods. 24 */ 25 class ClassWidePolicyPropagatingFilter( 26 private val classes: ClassNodes, 27 fallback: OutputFilter, 28 ) : DelegatingFilter(fallback) { 29 30 private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? { 31 var currentClass = className 32 33 34 // If the class name is `a.b.c.A$B$C`, then we try to get the class wide policy 35 // from a.b.c.A$B$C, then a.b.c.A$B, and then a.b.c.A. 36 while (true) { 37 // Sometimes a class name has a `$` in it but not as a nest class name separator -- 38 // e.g. class name like "MyClass$$". In this case, `MyClass$` may not actually be 39 // a class name. 40 // So before getting the class policy on a nonexistent class, which may cause an 41 // incorrect result, we make sure if className actually exists. 42 if (classes.hasClass(className)) { 43 outermostFilter.getPolicyForClass(className).let { policy -> 44 if (policy.policy.isClassWidePolicy) { 45 val p = if (resolve) { 46 policy.policy.resolveClassWidePolicy() 47 } else { 48 policy.policy 49 } 50 51 return p.withReason(policy.reason) 52 .wrapReason("class-wide in $currentClass") 53 } 54 // If the class's policy is remove, then remove it. 55 if (policy.policy == FilterPolicy.Remove) { 56 return FilterPolicy.Remove.withReason("class-wide in $currentClass") 57 } 58 } 59 } 60 61 // Next, look at the outer class... 62 val outer = getDirectOuterClassName(currentClass) 63 if (outer == null) { 64 return null 65 } 66 currentClass = outer 67 } 68 } 69 70 override fun getPolicyForClass(className: String): FilterPolicyWithReason { 71 // If it's a nested class, use the outer class's policy. 72 getDirectOuterClassName(className)?.let { outerName -> 73 getClassWidePolicy(outerName, resolve = false)?.let { policy -> 74 return policy 75 } 76 } 77 78 return super.getPolicyForClass(className) 79 } 80 81 override fun getPolicyForField( 82 className: String, 83 fieldName: String 84 ): FilterPolicyWithReason { 85 return getClassWidePolicy(className, resolve = true) 86 ?: super.getPolicyForField(className, fieldName) 87 } 88 89 override fun getPolicyForMethod( 90 className: String, 91 methodName: String, 92 descriptor: String 93 ): FilterPolicyWithReason { 94 return getClassWidePolicy(className, resolve = true) 95 ?: super.getPolicyForMethod(className, methodName, descriptor) 96 } 97 }