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 */ 30package org.mockito.asm.tree.analysis; 31 32import java.util.List; 33 34import 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 */ 44public 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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