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 * Explicit type cast.
25 */
26public class Cast extends Expr {
27    /**
28     * Undocumented constructor.  Do not use; internal-use only.
29     */
30    protected Cast(int pos, CodeIterator i, CtClass declaring, MethodInfo m) {
31        super(pos, i, declaring, m);
32    }
33
34    /**
35     * Returns the method or constructor containing the type cast
36     * expression represented by this object.
37     */
38    public CtBehavior where() { return super.where(); }
39
40    /**
41     * Returns the line number of the source line containing the
42     * type-cast expression.
43     *
44     * @return -1       if this information is not available.
45     */
46    public int getLineNumber() {
47        return super.getLineNumber();
48    }
49
50    /**
51     * Returns the source file containing the type-cast expression.
52     *
53     * @return null     if this information is not available.
54     */
55    public String getFileName() {
56        return super.getFileName();
57    }
58
59    /**
60     * Returns the <code>CtClass</code> object representing
61     * the type specified by the cast.
62     */
63    public CtClass getType() throws NotFoundException {
64        ConstPool cp = getConstPool();
65        int pos = currentPos;
66        int index = iterator.u16bitAt(pos + 1);
67        String name = cp.getClassInfo(index);
68        return thisClass.getClassPool().getCtClass(name);
69    }
70
71    /**
72     * Returns the list of exceptions that the expression may throw.
73     * This list includes both the exceptions that the try-catch statements
74     * including the expression can catch and the exceptions that
75     * the throws declaration allows the method to throw.
76     */
77    public CtClass[] mayThrow() {
78        return super.mayThrow();
79    }
80
81    /**
82     * Replaces the explicit cast operator with the bytecode derived from
83     * the given source text.
84     *
85     * <p>$0 is available but the value is <code>null</code>.
86     *
87     * @param statement         a Java statement except try-catch.
88     */
89    public void replace(String statement) throws CannotCompileException {
90        thisClass.getClassFile();   // to call checkModify().
91        ConstPool constPool = getConstPool();
92        int pos = currentPos;
93        int index = iterator.u16bitAt(pos + 1);
94
95        Javac jc = new Javac(thisClass);
96        ClassPool cp = thisClass.getClassPool();
97        CodeAttribute ca = iterator.get();
98
99        try {
100            CtClass[] params
101                = new CtClass[] { cp.get(javaLangObject) };
102            CtClass retType = getType();
103
104            int paramVar = ca.getMaxLocals();
105            jc.recordParams(javaLangObject, params, true, paramVar,
106                            withinStatic());
107            int retVar = jc.recordReturnType(retType, true);
108            jc.recordProceed(new ProceedForCast(index, retType));
109
110            /* Is $_ included in the source code?
111             */
112            checkResultValue(retType, statement);
113
114            Bytecode bytecode = jc.getBytecode();
115            storeStack(params, true, paramVar, bytecode);
116            jc.recordLocalVariables(ca, pos);
117
118            bytecode.addConstZero(retType);
119            bytecode.addStore(retVar, retType);     // initialize $_
120
121            jc.compileStmnt(statement);
122            bytecode.addLoad(retVar, retType);
123
124            replace0(pos, bytecode, 3);
125        }
126        catch (CompileError e) { throw new CannotCompileException(e); }
127        catch (NotFoundException e) { throw new CannotCompileException(e); }
128        catch (BadBytecode e) {
129            throw new CannotCompileException("broken method");
130        }
131    }
132
133    /* <type> $proceed(Object obj)
134     */
135    static class ProceedForCast implements ProceedHandler {
136        int index;
137        CtClass retType;
138
139        ProceedForCast(int i, CtClass t) {
140            index = i;
141            retType = t;
142        }
143
144        public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
145            throws CompileError
146        {
147            if (gen.getMethodArgsLength(args) != 1)
148                throw new CompileError(Javac.proceedName
149                        + "() cannot take more than one parameter "
150                        + "for cast");
151
152            gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
153            bytecode.addOpcode(Opcode.CHECKCAST);
154            bytecode.addIndex(index);
155            gen.setType(retType);
156        }
157
158        public void setReturnType(JvstTypeChecker c, ASTList args)
159            throws CompileError
160        {
161            c.atMethodArgs(args, new int[1], new int[1], new String[1]);
162            c.setType(retType);
163        }
164    }
165}
166