001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package org.ejb3unit.asm.tree.analysis;
030:
031: import java.util.List;
032:
033: import org.ejb3unit.asm.Type;
034:
035: /**
036: * An extended {@link BasicVerifier} that performs more precise verifications.
037: * This verifier computes exact class types, instead of using a single "object
038: * reference" type (as done in the {@link BasicVerifier}).
039: *
040: * @author Eric Bruneton
041: * @author Bing Ran
042: */
043: public class SimpleVerifier extends BasicVerifier {
044:
045: /**
046: * The class that is verified.
047: */
048: private final Type currentClass;
049:
050: /**
051: * The super class of the class that is verified.
052: */
053: private final Type currentSuperClass;
054:
055: /**
056: * The interfaces implemented by the class that is verified.
057: */
058: private final List currentClassInterfaces;
059:
060: /**
061: * If the class that is verified is an interface.
062: */
063: private final boolean isInterface;
064:
065: /**
066: * Constructs a new {@link SimpleVerifier}.
067: */
068: public SimpleVerifier() {
069: this (null, null, false);
070: }
071:
072: /**
073: * Constructs a new {@link SimpleVerifier} to verify a specific class. This
074: * class will not be loaded into the JVM since it may be incorrect.
075: *
076: * @param currentClass the class that is verified.
077: * @param currentSuperClass the super class of the class that is verified.
078: * @param isInterface if the class that is verified is an interface.
079: */
080: public SimpleVerifier(final Type currentClass,
081: final Type currentSuperClass, final boolean isInterface) {
082: this (currentClass, currentSuperClass, null, isInterface);
083: }
084:
085: /**
086: * Constructs a new {@link SimpleVerifier} to verify a specific class. This
087: * class will not be loaded into the JVM since it may be incorrect.
088: *
089: * @param currentClass the class that is verified.
090: * @param currentSuperClass the super class of the class that is verified.
091: * @param currentClassInterfaces the interfaces implemented by the class
092: * that is verified.
093: * @param isInterface if the class that is verified is an interface.
094: */
095: public SimpleVerifier(final Type currentClass,
096: final Type currentSuperClass,
097: final List currentClassInterfaces, final boolean isInterface) {
098: this .currentClass = currentClass;
099: this .currentSuperClass = currentSuperClass;
100: this .currentClassInterfaces = currentClassInterfaces;
101: this .isInterface = isInterface;
102: }
103:
104: public Value newValue(final Type type) {
105: if (type == null) {
106: return BasicValue.UNINITIALIZED_VALUE;
107: }
108:
109: boolean isArray = type.getSort() == Type.ARRAY;
110: if (isArray) {
111: switch (type.getElementType().getSort()) {
112: case Type.BOOLEAN:
113: case Type.CHAR:
114: case Type.BYTE:
115: case Type.SHORT:
116: return new BasicValue(type);
117: }
118: }
119:
120: Value v = super .newValue(type);
121: if (v == BasicValue.REFERENCE_VALUE) {
122: if (isArray) {
123: v = newValue(type.getElementType());
124: String desc = ((BasicValue) v).getType()
125: .getDescriptor();
126: for (int i = 0; i < type.getDimensions(); ++i) {
127: desc = "[" + desc;
128: }
129: v = new BasicValue(Type.getType(desc));
130: } else {
131: v = new BasicValue(type);
132: }
133: }
134: return v;
135: }
136:
137: protected boolean isArrayValue(final Value value) {
138: Type t = ((BasicValue) value).getType();
139: return t != null
140: && (t.getDescriptor().equals("Lnull;") || t.getSort() == Type.ARRAY);
141: }
142:
143: protected Value getElementValue(final Value objectArrayValue)
144: throws AnalyzerException {
145: Type arrayType = ((BasicValue) objectArrayValue).getType();
146: if (arrayType != null) {
147: if (arrayType.getSort() == Type.ARRAY) {
148: return newValue(Type.getType(arrayType.getDescriptor()
149: .substring(1)));
150: } else if (arrayType.getDescriptor().equals("Lnull;")) {
151: return objectArrayValue;
152: }
153: }
154: throw new Error("Internal error");
155: }
156:
157: protected boolean isSubTypeOf(final Value value,
158: final Value expected) {
159: Type expectedType = ((BasicValue) expected).getType();
160: Type type = ((BasicValue) value).getType();
161: switch (expectedType.getSort()) {
162: case Type.INT:
163: case Type.FLOAT:
164: case Type.LONG:
165: case Type.DOUBLE:
166: return type == expectedType;
167: case Type.ARRAY:
168: case Type.OBJECT:
169: if (type.getDescriptor().equals("Lnull;")) {
170: return true;
171: } else if (type.getSort() == Type.OBJECT
172: || type.getSort() == Type.ARRAY) {
173: return isAssignableFrom(expectedType, type);
174: } else {
175: return false;
176: }
177: default:
178: throw new Error("Internal error");
179: }
180: }
181:
182: public Value merge(final Value v, final Value w) {
183: if (!v.equals(w)) {
184: Type t = ((BasicValue) v).getType();
185: Type u = ((BasicValue) w).getType();
186: if (t != null
187: && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
188: if (u != null
189: && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
190: if (t.getDescriptor().equals("Lnull;")) {
191: return w;
192: }
193: if (u.getDescriptor().equals("Lnull;")) {
194: return v;
195: }
196: if (isAssignableFrom(t, u)) {
197: return v;
198: }
199: if (isAssignableFrom(u, t)) {
200: return w;
201: }
202: // TODO case of array classes of the same dimension
203: // TODO should we look also for a common super interface?
204: // problem: there may be several possible common super
205: // interfaces
206: do {
207: if (t == null || isInterface(t)) {
208: return BasicValue.REFERENCE_VALUE;
209: }
210: t = getSuperClass(t);
211: if (isAssignableFrom(t, u)) {
212: return newValue(t);
213: }
214: } while (true);
215: }
216: }
217: return BasicValue.UNINITIALIZED_VALUE;
218: }
219: return v;
220: }
221:
222: protected boolean isInterface(final Type t) {
223: if (currentClass != null && t.equals(currentClass)) {
224: return isInterface;
225: }
226: return getClass(t).isInterface();
227: }
228:
229: protected Type getSuperClass(final Type t) {
230: if (currentClass != null && t.equals(currentClass)) {
231: return currentSuperClass;
232: }
233: Class c = getClass(t).getSuperclass();
234: return c == null ? null : Type.getType(c);
235: }
236:
237: protected boolean isAssignableFrom(final Type t, final Type u) {
238: if (t.equals(u)) {
239: return true;
240: }
241: if (currentClass != null && t.equals(currentClass)) {
242: if (getSuperClass(u) == null) {
243: return false;
244: } else {
245: return isAssignableFrom(t, getSuperClass(u));
246: }
247: }
248: if (currentClass != null && u.equals(currentClass)) {
249: if (isAssignableFrom(t, currentSuperClass)) {
250: return true;
251: }
252: if (currentClassInterfaces != null) {
253: for (int i = 0; i < currentClassInterfaces.size(); ++i) {
254: Type v = (Type) currentClassInterfaces.get(i);
255: if (isAssignableFrom(t, v)) {
256: return true;
257: }
258: }
259: }
260: return false;
261: }
262: return getClass(t).isAssignableFrom(getClass(u));
263: }
264:
265: protected Class getClass(final Type t) {
266: try {
267: if (t.getSort() == Type.ARRAY) {
268: return Class.forName(t.getDescriptor()
269: .replace('/', '.'));
270: }
271: return Class.forName(t.getClassName());
272: } catch (ClassNotFoundException e) {
273: throw new RuntimeException(e.toString());
274: }
275: }
276: }
|