1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.expr;
17
18import javassist.*;
19import javassist.bytecode.*;
20import javassist.compiler.*;
21import javassist.compiler.ast.ASTList;
22
23/**
24 * Instanceof operator.
25 */
26public class Instanceof extends Expr {
27    /**
28     * Undocumented constructor.  Do not use; internal-use only.
29     */
30    protected Instanceof(int pos, CodeIterator i, CtClass declaring,
31                         MethodInfo m) {
32        super(pos, i, declaring, m);
33    }
34
35    /**
36     * Returns the method or constructor containing the instanceof
37     * expression represented by this object.
38     */
39    public CtBehavior where() { return super.where(); }
40
41    /**
42     * Returns the line number of the source line containing the
43     * instanceof expression.
44     *
45     * @return -1       if this information is not available.
46     */
47    public int getLineNumber() {
48        return super.getLineNumber();
49    }
50
51    /**
52     * Returns the source file containing the
53     * instanceof expression.
54     *
55     * @return null     if this information is not available.
56     */
57    public String getFileName() {
58        return super.getFileName();
59    }
60
61    /**
62     * Returns the <code>CtClass</code> object representing
63     * the type name on the right hand side
64     * of the instanceof operator.
65     */
66    public CtClass getType() throws NotFoundException {
67        ConstPool cp = getConstPool();
68        int pos = currentPos;
69        int index = iterator.u16bitAt(pos + 1);
70        String name = cp.getClassInfo(index);
71        return thisClass.getClassPool().getCtClass(name);
72    }
73
74    /**
75     * Returns the list of exceptions that the expression may throw.
76     * This list includes both the exceptions that the try-catch statements
77     * including the expression can catch and the exceptions that
78     * the throws declaration allows the method to throw.
79     */
80    public CtClass[] mayThrow() {
81        return super.mayThrow();
82    }
83
84    /**
85     * Replaces the instanceof operator with the bytecode derived from
86     * the given source text.
87     *
88     * <p>$0 is available but the value is <code>null</code>.
89     *
90     * @param statement         a Java statement except try-catch.
91     */
92    public void replace(String statement) throws CannotCompileException {
93        thisClass.getClassFile();   // to call checkModify().
94        ConstPool constPool = getConstPool();
95        int pos = currentPos;
96        int index = iterator.u16bitAt(pos + 1);
97
98        Javac jc = new Javac(thisClass);
99        ClassPool cp = thisClass.getClassPool();
100        CodeAttribute ca = iterator.get();
101
102        try {
103            CtClass[] params
104                = new CtClass[] { cp.get(javaLangObject) };
105            CtClass retType = CtClass.booleanType;
106
107            int paramVar = ca.getMaxLocals();
108            jc.recordParams(javaLangObject, params, true, paramVar,
109                            withinStatic());
110            int retVar = jc.recordReturnType(retType, true);
111            jc.recordProceed(new ProceedForInstanceof(index));
112
113            // because $type is not the return type...
114            jc.recordType(getType());
115
116            /* Is $_ included in the source code?
117             */
118            checkResultValue(retType, statement);
119
120            Bytecode bytecode = jc.getBytecode();
121            storeStack(params, true, paramVar, bytecode);
122            jc.recordLocalVariables(ca, pos);
123
124            bytecode.addConstZero(retType);
125            bytecode.addStore(retVar, retType);     // initialize $_
126
127            jc.compileStmnt(statement);
128            bytecode.addLoad(retVar, retType);
129
130            replace0(pos, bytecode, 3);
131        }
132        catch (CompileError e) { throw new CannotCompileException(e); }
133        catch (NotFoundException e) { throw new CannotCompileException(e); }
134        catch (BadBytecode e) {
135            throw new CannotCompileException("broken method");
136        }
137    }
138
139    /* boolean $proceed(Object obj)
140     */
141    static class ProceedForInstanceof implements ProceedHandler {
142        int index;
143
144        ProceedForInstanceof(int i) {
145            index = i;
146        }
147
148        public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
149            throws CompileError
150        {
151            if (gen.getMethodArgsLength(args) != 1)
152                throw new CompileError(Javac.proceedName
153                        + "() cannot take more than one parameter "
154                        + "for instanceof");
155
156            gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
157            bytecode.addOpcode(Opcode.INSTANCEOF);
158            bytecode.addIndex(index);
159            gen.setType(CtClass.booleanType);
160        }
161
162        public void setReturnType(JvstTypeChecker c, ASTList args)
163            throws CompileError
164        {
165            c.atMethodArgs(args, new int[1], new int[1], new String[1]);
166            c.setType(CtClass.booleanType);
167        }
168    }
169}
170