169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.expr;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.*;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.*;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.ast.ASTList;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Explicit type cast.
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Cast extends Expr {
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Undocumented constructor.  Do not use; internal-use only.
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected Cast(int pos, CodeIterator i, CtClass declaring, MethodInfo m) {
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super(pos, i, declaring, m);
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the method or constructor containing the type cast
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * expression represented by this object.
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtBehavior where() { return super.where(); }
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the line number of the source line containing the
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * type-cast expression.
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return -1       if this information is not available.
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int getLineNumber() {
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return super.getLineNumber();
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the source file containing the type-cast expression.
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return null     if this information is not available.
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getFileName() {
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return super.getFileName();
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the <code>CtClass</code> object representing
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the type specified by the cast.
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtClass getType() throws NotFoundException {
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool cp = getConstPool();
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int pos = currentPos;
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int index = iterator.u16bitAt(pos + 1);
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String name = cp.getClassInfo(index);
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return thisClass.getClassPool().getCtClass(name);
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the list of exceptions that the expression may throw.
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This list includes both the exceptions that the try-catch statements
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * including the expression can catch and the exceptions that
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the throws declaration allows the method to throw.
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtClass[] mayThrow() {
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return super.mayThrow();
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Replaces the explicit cast operator with the bytecode derived from
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the given source text.
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>$0 is available but the value is <code>null</code>.
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param statement         a Java statement except try-catch.
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void replace(String statement) throws CannotCompileException {
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        thisClass.getClassFile();   // to call checkModify().
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool constPool = getConstPool();
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int pos = currentPos;
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int index = iterator.u16bitAt(pos + 1);
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Javac jc = new Javac(thisClass);
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassPool cp = thisClass.getClassPool();
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute ca = iterator.get();
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtClass[] params
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                = new CtClass[] { cp.get(javaLangObject) };
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtClass retType = getType();
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int paramVar = ca.getMaxLocals();
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jc.recordParams(javaLangObject, params, true, paramVar,
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            withinStatic());
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int retVar = jc.recordReturnType(retType, true);
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jc.recordProceed(new ProceedForCast(index, retType));
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            /* Is $_ included in the source code?
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             */
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            checkResultValue(retType, statement);
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Bytecode bytecode = jc.getBytecode();
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            storeStack(params, true, paramVar, bytecode);
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jc.recordLocalVariables(ca, pos);
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            bytecode.addConstZero(retType);
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            bytecode.addStore(retVar, retType);     // initialize $_
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jc.compileStmnt(statement);
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            bytecode.addLoad(retVar, retType);
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            replace0(pos, bytecode, 3);
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (CompileError e) { throw new CannotCompileException(e); }
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NotFoundException e) { throw new CannotCompileException(e); }
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadBytecode e) {
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException("broken method");
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* <type> $proceed(Object obj)
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    static class ProceedForCast implements ProceedHandler {
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int index;
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass retType;
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ProceedForCast(int i, CtClass t) {
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            index = i;
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            retType = t;
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throws CompileError
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        {
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (gen.getMethodArgsLength(args) != 1)
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new CompileError(Javac.proceedName
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        + "() cannot take more than one parameter "
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        + "for cast");
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            bytecode.addOpcode(Opcode.CHECKCAST);
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            bytecode.addIndex(index);
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            gen.setType(retType);
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        public void setReturnType(JvstTypeChecker c, ASTList args)
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throws CompileError
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        {
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            c.atMethodArgs(args, new int[1], new int[1], new String[1]);
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            c.setType(retType);
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
166