1baa3858d3f5d128a5c8466b700098109edcad5f2repo sync/***
2baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * ASM: a very small and fast Java bytecode manipulation framework
3baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * Copyright (c) 2000-2007 INRIA, France Telecom
4baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * All rights reserved.
5baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *
6baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * Redistribution and use in source and binary forms, with or without
7baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * modification, are permitted provided that the following conditions
8baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * are met:
9baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 1. Redistributions of source code must retain the above copyright
10baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *    notice, this list of conditions and the following disclaimer.
11baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 2. Redistributions in binary form must reproduce the above copyright
12baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *    notice, this list of conditions and the following disclaimer in the
13baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *    documentation and/or other materials provided with the distribution.
14baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * 3. Neither the name of the copyright holders nor the names of its
15baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *    contributors may be used to endorse or promote products derived from
16baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *    this software without specific prior written permission.
17baa3858d3f5d128a5c8466b700098109edcad5f2repo sync *
18baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28baa3858d3f5d128a5c8466b700098109edcad5f2repo sync * THE POSSIBILITY OF SUCH DAMAGE.
29baa3858d3f5d128a5c8466b700098109edcad5f2repo sync */
30baa3858d3f5d128a5c8466b700098109edcad5f2repo syncpackage org.mockito.asm.tree.analysis;
31baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
32baa3858d3f5d128a5c8466b700098109edcad5f2repo syncimport java.util.List;
33baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
34baa3858d3f5d128a5c8466b700098109edcad5f2repo syncimport org.mockito.asm.Type;
35baa3858d3f5d128a5c8466b700098109edcad5f2repo sync
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