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