• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2007 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 package org.mockito.asm.tree.analysis;
31 
32 import java.util.List;
33 
34 import org.mockito.asm.Type;
35 
36 /**
37  * An extended {@link BasicVerifier} that performs more precise verifications.
38  * This verifier computes exact class types, instead of using a single "object
39  * reference" type (as done in the {@link BasicVerifier}).
40  *
41  * @author Eric Bruneton
42  * @author Bing Ran
43  */
44 public class SimpleVerifier extends BasicVerifier {
45 
46     /**
47      * The class that is verified.
48      */
49     private final Type currentClass;
50 
51     /**
52      * The super class of the class that is verified.
53      */
54     private final Type currentSuperClass;
55 
56     /**
57      * The interfaces implemented by the class that is verified.
58      */
59     private final List currentClassInterfaces;
60 
61     /**
62      * If the class that is verified is an interface.
63      */
64     private final boolean isInterface;
65 
66     /**
67      * Constructs a new {@link SimpleVerifier}.
68      */
SimpleVerifier()69     public SimpleVerifier() {
70         this(null, null, false);
71     }
72 
73     /**
74      * Constructs a new {@link SimpleVerifier} to verify a specific class. This
75      * class will not be loaded into the JVM since it may be incorrect.
76      *
77      * @param currentClass the class that is verified.
78      * @param currentSuperClass the super class of the class that is verified.
79      * @param isInterface if the class that is verified is an interface.
80      */
SimpleVerifier( final Type currentClass, final Type currentSuperClass, final boolean isInterface)81     public SimpleVerifier(
82         final Type currentClass,
83         final Type currentSuperClass,
84         final boolean isInterface)
85     {
86         this(currentClass, currentSuperClass, null, isInterface);
87     }
88 
89     /**
90      * Constructs a new {@link SimpleVerifier} to verify a specific class. This
91      * class will not be loaded into the JVM since it may be incorrect.
92      *
93      * @param currentClass the class that is verified.
94      * @param currentSuperClass the super class of the class that is verified.
95      * @param currentClassInterfaces the interfaces implemented by the class
96      *        that is verified.
97      * @param isInterface if the class that is verified is an interface.
98      */
SimpleVerifier( final Type currentClass, final Type currentSuperClass, final List currentClassInterfaces, final boolean isInterface)99     public SimpleVerifier(
100         final Type currentClass,
101         final Type currentSuperClass,
102         final List currentClassInterfaces,
103         final boolean isInterface)
104     {
105         this.currentClass = currentClass;
106         this.currentSuperClass = currentSuperClass;
107         this.currentClassInterfaces = currentClassInterfaces;
108         this.isInterface = isInterface;
109     }
110 
newValue(final Type type)111     public Value newValue(final Type type) {
112         if (type == null) {
113             return BasicValue.UNINITIALIZED_VALUE;
114         }
115 
116         boolean isArray = type.getSort() == Type.ARRAY;
117         if (isArray) {
118             switch (type.getElementType().getSort()) {
119                 case Type.BOOLEAN:
120                 case Type.CHAR:
121                 case Type.BYTE:
122                 case Type.SHORT:
123                     return new BasicValue(type);
124             }
125         }
126 
127         Value v = super.newValue(type);
128         if (v == BasicValue.REFERENCE_VALUE) {
129             if (isArray) {
130                 v = newValue(type.getElementType());
131                 String desc = ((BasicValue) v).getType().getDescriptor();
132                 for (int i = 0; i < type.getDimensions(); ++i) {
133                     desc = '[' + desc;
134                 }
135                 v = new BasicValue(Type.getType(desc));
136             } else {
137                 v = new BasicValue(type);
138             }
139         }
140         return v;
141     }
142 
isArrayValue(final Value value)143     protected boolean isArrayValue(final Value value) {
144         Type t = ((BasicValue) value).getType();
145         return t != null
146                 && ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
147     }
148 
getElementValue(final Value objectArrayValue)149     protected Value getElementValue(final Value objectArrayValue)
150             throws AnalyzerException
151     {
152         Type arrayType = ((BasicValue) objectArrayValue).getType();
153         if (arrayType != null) {
154             if (arrayType.getSort() == Type.ARRAY) {
155                 return newValue(Type.getType(arrayType.getDescriptor()
156                         .substring(1)));
157             } else if ("Lnull;".equals(arrayType.getDescriptor())) {
158                 return objectArrayValue;
159             }
160         }
161         throw new Error("Internal error");
162     }
163 
isSubTypeOf(final Value value, final Value expected)164     protected boolean isSubTypeOf(final Value value, final Value expected) {
165         Type expectedType = ((BasicValue) expected).getType();
166         Type type = ((BasicValue) value).getType();
167         switch (expectedType.getSort()) {
168             case Type.INT:
169             case Type.FLOAT:
170             case Type.LONG:
171             case Type.DOUBLE:
172                 return type == expectedType;
173             case Type.ARRAY:
174             case Type.OBJECT:
175                 if ("Lnull;".equals(type.getDescriptor())) {
176                     return true;
177                 } else if (type.getSort() == Type.OBJECT
178                         || type.getSort() == Type.ARRAY)
179                 {
180                     return isAssignableFrom(expectedType, type);
181                 } else {
182                     return false;
183                 }
184             default:
185                 throw new Error("Internal error");
186         }
187     }
188 
merge(final Value v, final Value w)189     public Value merge(final Value v, final Value w) {
190         if (!v.equals(w)) {
191             Type t = ((BasicValue) v).getType();
192             Type u = ((BasicValue) w).getType();
193             if (t != null
194                     && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY))
195             {
196                 if (u != null
197                         && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY))
198                 {
199                     if ("Lnull;".equals(t.getDescriptor())) {
200                         return w;
201                     }
202                     if ("Lnull;".equals(u.getDescriptor())) {
203                         return v;
204                     }
205                     if (isAssignableFrom(t, u)) {
206                         return v;
207                     }
208                     if (isAssignableFrom(u, t)) {
209                         return w;
210                     }
211                     // TODO case of array classes of the same dimension
212                     // TODO should we look also for a common super interface?
213                     // problem: there may be several possible common super
214                     // interfaces
215                     do {
216                         if (t == null || isInterface(t)) {
217                             return BasicValue.REFERENCE_VALUE;
218                         }
219                         t = getSuperClass(t);
220                         if (isAssignableFrom(t, u)) {
221                             return newValue(t);
222                         }
223                     } while (true);
224                 }
225             }
226             return BasicValue.UNINITIALIZED_VALUE;
227         }
228         return v;
229     }
230 
isInterface(final Type t)231     protected boolean isInterface(final Type t) {
232         if (currentClass != null && t.equals(currentClass)) {
233             return isInterface;
234         }
235         return getClass(t).isInterface();
236     }
237 
getSuperClass(final Type t)238     protected Type getSuperClass(final Type t) {
239         if (currentClass != null && t.equals(currentClass)) {
240             return currentSuperClass;
241         }
242         Class c = getClass(t).getSuperclass();
243         return c == null ? null : Type.getType(c);
244     }
245 
isAssignableFrom(final Type t, final Type u)246     protected boolean isAssignableFrom(final Type t, final Type u) {
247         if (t.equals(u)) {
248             return true;
249         }
250         if (currentClass != null && t.equals(currentClass)) {
251             if (getSuperClass(u) == null) {
252                 return false;
253             } else {
254                 return isAssignableFrom(t, getSuperClass(u));
255             }
256         }
257         if (currentClass != null && u.equals(currentClass)) {
258             if (isAssignableFrom(t, currentSuperClass)) {
259                 return true;
260             }
261             if (currentClassInterfaces != null) {
262                 for (int i = 0; i < currentClassInterfaces.size(); ++i) {
263                     Type v = (Type) currentClassInterfaces.get(i);
264                     if (isAssignableFrom(t, v)) {
265                         return true;
266                     }
267                 }
268             }
269             return false;
270         }
271         return getClass(t).isAssignableFrom(getClass(u));
272     }
273 
getClass(final Type t)274     protected Class getClass(final Type t) {
275         try {
276             if (t.getSort() == Type.ARRAY) {
277                 return Class.forName(t.getDescriptor().replace('/', '.'));
278             }
279             return Class.forName(t.getClassName());
280         } catch (ClassNotFoundException e) {
281             throw new RuntimeException(e.toString());
282         }
283     }
284 }
285