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