1 /*
2  * 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.visitors
17 
18 import com.android.hoststubgen.HostStubGenErrors
19 import com.android.hoststubgen.asm.ClassNodes
20 import com.android.hoststubgen.asm.clearVisibility
21 import com.android.hoststubgen.asm.getVisibility
22 import com.android.hoststubgen.asm.isStatic
23 
24 const val NOT_COMPATIBLE: Int = -1
25 
26 /**
27  * Make sure substitution from and to methods have matching definition.
28  * (static-ness, etc)
29  *
30  * If the methods are compatible, return the "merged" [access] of the new method.
31  *
32  * If they are not compatible, returns [NOT_COMPATIBLE]
33  */
checkSubstitutionMethodCompatibilitynull34 fun checkSubstitutionMethodCompatibility(
35     classes: ClassNodes,
36     className: String,
37     fromMethodName: String, // the one with the annotation
38     toMethodName: String, // the one with either a "_host" or "$ravenwood" prefix. (typically)
39     descriptor: String,
40     errors: HostStubGenErrors,
41 ): Int {
42     val from = classes.findMethod(className, fromMethodName, descriptor)
43     if (from == null) {
44         errors.onErrorFound(
45             "Substitution-from method not found: $className.$fromMethodName$descriptor"
46         )
47         return NOT_COMPATIBLE
48     }
49     val to = classes.findMethod(className, toMethodName, descriptor)
50     if (to == null) {
51         // This shouldn't happen, because the visitor visited this method...
52         errors.onErrorFound(
53             "Substitution-to method not found: $className.$toMethodName$descriptor"
54         )
55         return NOT_COMPATIBLE
56     }
57 
58     if (from.isStatic() != to.isStatic()) {
59         errors.onErrorFound(
60             "Substitution method must have matching static-ness: " +
61                     "$className.$fromMethodName$descriptor"
62         )
63         return NOT_COMPATIBLE
64     }
65 
66     // Return the substitution's access flag but with the original method's visibility.
67     return clearVisibility (to.access) or getVisibility(from.access)
68 }
69