/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later, * or the Apache License Version 2.0. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */ package javassist.expr; import javassist.*; import javassist.bytecode.*; import javassist.compiler.*; import javassist.compiler.ast.ASTList; /** * Expression for accessing a field. */ public class FieldAccess extends Expr { int opcode; protected FieldAccess(int pos, CodeIterator i, CtClass declaring, MethodInfo m, int op) { super(pos, i, declaring, m); opcode = op; } /** * Returns the method or constructor containing the field-access * expression represented by this object. */ public CtBehavior where() { return super.where(); } /** * Returns the line number of the source line containing the * field access. * * @return -1 if this information is not available. */ public int getLineNumber() { return super.getLineNumber(); } /** * Returns the source file containing the field access. * * @return null if this information is not available. */ public String getFileName() { return super.getFileName(); } /** * Returns true if the field is static. */ public boolean isStatic() { return isStatic(opcode); } static boolean isStatic(int c) { return c == Opcode.GETSTATIC || c == Opcode.PUTSTATIC; } /** * Returns true if the field is read. */ public boolean isReader() { return opcode == Opcode.GETFIELD || opcode == Opcode.GETSTATIC; } /** * Returns true if the field is written in. */ public boolean isWriter() { return opcode == Opcode.PUTFIELD || opcode == Opcode.PUTSTATIC; } /** * Returns the class in which the field is declared. */ private CtClass getCtClass() throws NotFoundException { return thisClass.getClassPool().get(getClassName()); } /** * Returns the name of the class in which the field is declared. */ public String getClassName() { int index = iterator.u16bitAt(currentPos + 1); return getConstPool().getFieldrefClassName(index); } /** * Returns the name of the field. */ public String getFieldName() { int index = iterator.u16bitAt(currentPos + 1); return getConstPool().getFieldrefName(index); } /** * Returns the field accessed by this expression. */ public CtField getField() throws NotFoundException { CtClass cc = getCtClass(); int index = iterator.u16bitAt(currentPos + 1); ConstPool cp = getConstPool(); return cc.getField(cp.getFieldrefName(index), cp.getFieldrefType(index)); //return cc.getField(getFieldName()); } /** * Returns the list of exceptions that the expression may throw. * This list includes both the exceptions that the try-catch statements * including the expression can catch and the exceptions that * the throws declaration allows the method to throw. */ public CtClass[] mayThrow() { return super.mayThrow(); } /** * Returns the signature of the field type. * The signature is represented by a character string * called field descriptor, which is defined in the JVM specification. * * @see javassist.bytecode.Descriptor#toCtClass(String, ClassPool) * @since 3.1 */ public String getSignature() { int index = iterator.u16bitAt(currentPos + 1); return getConstPool().getFieldrefType(index); } /** * Replaces the method call with the bytecode derived from * the given source text. * *
$0 is available even if the called method is static.
* If the field access is writing, $_ is available but the value
* of $_ is ignored.
*
* @param statement a Java statement except try-catch.
*/
public void replace(String statement) throws CannotCompileException {
thisClass.getClassFile(); // to call checkModify().
ConstPool constPool = getConstPool();
int pos = currentPos;
int index = iterator.u16bitAt(pos + 1);
Javac jc = new Javac(thisClass);
CodeAttribute ca = iterator.get();
try {
CtClass[] params;
CtClass retType;
CtClass fieldType
= Descriptor.toCtClass(constPool.getFieldrefType(index),
thisClass.getClassPool());
boolean read = isReader();
if (read) {
params = new CtClass[0];
retType = fieldType;
}
else {
params = new CtClass[1];
params[0] = fieldType;
retType = CtClass.voidType;
}
int paramVar = ca.getMaxLocals();
jc.recordParams(constPool.getFieldrefClassName(index), params,
true, paramVar, withinStatic());
/* Is $_ included in the source code?
*/
boolean included = checkResultValue(retType, statement);
if (read)
included = true;
int retVar = jc.recordReturnType(retType, included);
if (read)
jc.recordProceed(new ProceedForRead(retType, opcode,
index, paramVar));
else {
// because $type is not the return type...
jc.recordType(fieldType);
jc.recordProceed(new ProceedForWrite(params[0], opcode,
index, paramVar));
}
Bytecode bytecode = jc.getBytecode();
storeStack(params, isStatic(), paramVar, bytecode);
jc.recordLocalVariables(ca, pos);
if (included)
if (retType == CtClass.voidType) {
bytecode.addOpcode(ACONST_NULL);
bytecode.addAstore(retVar);
}
else {
bytecode.addConstZero(retType);
bytecode.addStore(retVar, retType); // initialize $_
}
jc.compileStmnt(statement);
if (read)
bytecode.addLoad(retVar, retType);
replace0(pos, bytecode, 3);
}
catch (CompileError e) { throw new CannotCompileException(e); }
catch (NotFoundException e) { throw new CannotCompileException(e); }
catch (BadBytecode e) {
throw new CannotCompileException("broken method");
}
}
/*