1 /*
2  * Copyright (C) 2007 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.dexgen.rop.cst;
18 
19 import com.android.dexgen.rop.type.Prototype;
20 import com.android.dexgen.rop.type.Type;
21 import com.android.dexgen.rop.type.TypeBearer;
22 
23 /**
24  * Base class for constants of "methodish" type.
25  *
26  * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type
27  * of the method.</p>
28  */
29 public abstract class CstBaseMethodRef
30         extends CstMemberRef {
31     /** {@code non-null;} the raw prototype for this method */
32     private final Prototype prototype;
33 
34     /**
35      * {@code null-ok;} the prototype for this method taken to be an instance
36      * method, or {@code null} if not yet calculated
37      */
38     private Prototype instancePrototype;
39 
40     /**
41      * Constructs an instance.
42      *
43      * @param definingClass {@code non-null;} the type of the defining class
44      * @param nat {@code non-null;} the name-and-type
45      */
CstBaseMethodRef(CstType definingClass, CstNat nat)46     /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) {
47         super(definingClass, nat);
48 
49         String descriptor = getNat().getDescriptor().getString();
50         this.prototype = Prototype.intern(descriptor);
51         this.instancePrototype = null;
52     }
53 
54     /**
55      * Gets the raw prototype of this method. This doesn't include a
56      * {@code this} argument.
57      *
58      * @return {@code non-null;} the method prototype
59      */
getPrototype()60     public final Prototype getPrototype() {
61         return prototype;
62     }
63 
64     /**
65      * Gets the prototype of this method as either a
66      * {@code static} or instance method. In the case of a
67      * {@code static} method, this is the same as the raw
68      * prototype. In the case of an instance method, this has an
69      * appropriately-typed {@code this} argument as the first
70      * one.
71      *
72      * @param isStatic whether the method should be considered static
73      * @return {@code non-null;} the method prototype
74      */
getPrototype(boolean isStatic)75     public final Prototype getPrototype(boolean isStatic) {
76         if (isStatic) {
77             return prototype;
78         } else {
79             if (instancePrototype == null) {
80                 Type thisType = getDefiningClass().getClassType();
81                 instancePrototype = prototype.withFirstParameter(thisType);
82             }
83             return instancePrototype;
84         }
85     }
86 
87     /** {@inheritDoc} */
88     @Override
compareTo0(Constant other)89     protected final int compareTo0(Constant other) {
90         int cmp = super.compareTo0(other);
91 
92         if (cmp != 0) {
93             return cmp;
94         }
95 
96         CstBaseMethodRef otherMethod = (CstBaseMethodRef) other;
97         return prototype.compareTo(otherMethod.prototype);
98     }
99 
100     /**
101      * {@inheritDoc}
102      *
103      * In this case, this method returns the <i>return type</i> of this method.
104      *
105      * @return {@code non-null;} the method's return type
106      */
getType()107     public final Type getType() {
108         return prototype.getReturnType();
109     }
110 
111     /**
112      * Gets the number of words of parameters required by this
113      * method's descriptor. Since instances of this class have no way
114      * to know if they will be used in a {@code static} or
115      * instance context, one has to indicate this explicitly as an
116      * argument. This method is just a convenient shorthand for
117      * {@code getPrototype().getParameterTypes().getWordCount()},
118      * plus {@code 1} if the method is to be treated as an
119      * instance method.
120      *
121      * @param isStatic whether the method should be considered static
122      * @return {@code >= 0;} the argument word count
123      */
getParameterWordCount(boolean isStatic)124     public final int getParameterWordCount(boolean isStatic) {
125         return getPrototype(isStatic).getParameterTypes().getWordCount();
126     }
127 
128     /**
129      * Gets whether this is a reference to an instance initialization
130      * method. This is just a convenient shorthand for
131      * {@code getNat().isInstanceInit()}.
132      *
133      * @return {@code true} iff this is a reference to an
134      * instance initialization method
135      */
isInstanceInit()136     public final boolean isInstanceInit() {
137         return getNat().isInstanceInit();
138     }
139 
140     /**
141      * Gets whether this is a reference to a class initialization
142      * method. This is just a convenient shorthand for
143      * {@code getNat().isClassInit()}.
144      *
145      * @return {@code true} iff this is a reference to an
146      * instance initialization method
147      */
isClassInit()148     public final boolean isClassInit() {
149         return getNat().isClassInit();
150     }
151 }
152