/*
* 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.
*
* MODIFIED BY James Nelson of We The Internet, 2013.
* Repackaged to avoid conflicts with different versions of Javassist,
* and modified Javassist APIs to make them more accessible to outside code.
*/
package xapi.bytecode;
import xapi.source.X_Modifier;
public final class CtMethod extends CtBehavior {
protected String cachedStringRep;
/**
* @see #make(MethodInfo minfo, CtClass declaring)
*/
CtMethod(MethodInfo minfo, CtClass declaring) {
super(declaring, minfo);
cachedStringRep = null;
}
/**
* Creates a public abstract method. The created method must be
* added to a class with <code>CtClass.addMethod()</code>.
*
* @param declaring the class to which the created method is added.
* @param returnType the type of the returned value
* @param mname the method name
* @param parameters a list of the parameter types
*
* @see CtClass#addMethod(CtMethod)
*/
public CtMethod(CtClass returnType, String mname,
CtClass[] parameters, CtClass declaring) {
this(null, declaring);
ConstPool cp = declaring.getClassFile2().getConstPool();
String desc = Descriptor.ofMethod(returnType, parameters);
methodInfo = new MethodInfo(cp, mname, desc);
setModifiers(X_Modifier.PUBLIC | X_Modifier.ABSTRACT);
}
// /**
// * Creates a copy of a <code>CtMethod</code> object.
// * The created method must be
// * added to a class with <code>CtClass.addMethod()</code>.
// *
// * <p>All occurrences of class names in the created method
// * are replaced with names specified by
// * <code>map</code> if <code>map</code> is not <code>null</code>.
// *
// * <p>For example, suppose that a method <code>at()</code> is as
// * follows:
// *
// * <ul><pre>public X at(int i) {
// * return (X)super.elementAt(i);
// * }</pre></ul>
// *
// * <p>(<code>X</code> is a class name.) If <code>map</code> substitutes
// * <code>String</code> for <code>X</code>, then the created method is:
// *
// * <ul><pre>public String at(int i) {
// * return (String)super.elementAt(i);
// * }</pre></ul>
// *
// * <p>By default, all the occurrences of the names of the class
// * declaring <code>at()</code> and the superclass are replaced
// * with the name of the class and the superclass that the
// * created method is added to.
// * This is done whichever <code>map</code> is null or not.
// * To prevent this replacement, call <code>ClassMap.fix()</code>
// * or <code>put()</code> to explicitly specify replacement.
// *
// * <p><b>Note:</b> if the <code>.class</code> notation (for example,
// * <code>String.class</code>) is included in an expression, the
// * Javac compiler may produce a helper method.
// * Since this constructor never
// * copies this helper method, the programmers have the responsiblity of
// * copying it. Otherwise, use <code>Class.forName()</code> in the
// * expression.
// *
// * @param src the source method.
// * @param declaring the class to which the created method is added.
// * @param map the hashtable associating original class names
// * with substituted names.
// * It can be <code>null</code>.
// *
// * @see CtClass#addMethod(CtMethod)
// * @see ClassMap#fix(String)
// */
// public CtMethod(CtMethod src, CtClass declaring, ClassMap map)
// throws CannotCompileException
// {
// this(null, declaring);
// copy(src, false, map);
// }
//
// /**
// * Compiles the given source code and creates a method.
// * This method simply delegates to <code>make()</code> in
// * <code>CtNewMethod</code>. See it for more details.
// * <code>CtNewMethod</code> has a number of useful factory methods.
// *
// * @param src the source text.
// * @param declaring the class to which the created method is added.
// * @see CtNewMethod#make(String, CtClass)
// */
// public static CtMethod make(String src, CtClass declaring)
// throws CannotCompileException
// {
// return CtNewMethod.make(src, declaring);
// }
/**
* Creates a method from a <code>MethodInfo</code> object.
*
* @param declaring the class declaring the method.
* @throws CannotCompileException if the the <code>MethodInfo</code>
* object and the declaring class have different
* <code>ConstPool</code> objects
* @since 3.6
*/
public static CtMethod make(MethodInfo minfo, CtClass declaring)
throws CannotCompileException
{
if (declaring.getClassFile2().getConstPool() != minfo.getConstPool()) {
throw new CannotCompileException("bad declaring class");
}
return new CtMethod(minfo, declaring);
}
/**
* Returns a hash code value for the method.
* If two methods have the same name and signature, then
* the hash codes for the two methods are equal.
*/
@Override
public int hashCode() {
return getStringRep().hashCode();
}
/**
* This method is invoked when setName() or replaceClassName()
* in CtClass is called.
*/
@Override
void nameReplaced() {
cachedStringRep = null;
}
/* This method is also called by CtClassType.getMethods0().
*/
final String getStringRep() {
if (cachedStringRep == null) {
cachedStringRep = methodInfo.getName()
+ Descriptor.getParamDescriptor(methodInfo.getDescriptor());
}
return cachedStringRep;
}
/**
* Indicates whether <code>obj</code> has the same name and the
* same signature as this method.
*/
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof CtMethod
&& ((CtMethod)obj).getStringRep().equals(getStringRep());
}
/**
* Returns the method name followed by parameter types
* such as <code>javassist.CtMethod.setBody(String)</code>.
*
* @since 3.5
*/
@Override
public String getLongName() {
return getDeclaringClass().getName() + "."
+ getName() + Descriptor.toString(getSignature());
}
/**
* Obtains the name of this method.
*/
@Override
public String getName() {
return methodInfo.getName();
}
/**
* Changes the name of this method.
*/
public void setName(String newname) {
declaringClass.checkModify();
methodInfo.setName(newname);
}
/**
* Obtains the type of the returned value.
*/
public CtClass getReturnType() throws NotFoundException {
return getReturnType0();
}
/**
* Returns true if the method body is empty, that is, <code>{}</code>.
* It also returns true if the method is an abstract method.
*/
@Override
public boolean isEmpty() {
return true;
}
public static class ConstParameter {
/**
* Makes an integer constant.
*
* @param i the constant value.
*/
public static ConstParameter integer(int i) {
return new IntConstParameter(i);
}
/**
* Makes a long integer constant.
*
* @param i the constant value.
*/
public static ConstParameter integer(long i) {
return new LongConstParameter(i);
}
/**
* Makes an <code>String</code> constant.
*
* @param s the constant value.
*/
public static ConstParameter string(String s) {
return new StringConstParameter(s);
}
ConstParameter() {}
/**
* @return the size of the stack consumption.
* @throws CannotCompileException
*/
int compile(Bytecode code) throws CannotCompileException {
return 0;
}
String descriptor() {
return defaultDescriptor();
}
/**
* @see CtNewWrappedMethod
*/
static String defaultDescriptor() {
return "([Ljava/lang/Object;)Ljava/lang/Object;";
}
/**
* Returns the descriptor for constructors.
*
* @see CtNewWrappedConstructor
*/
String constDescriptor() {
return defaultConstDescriptor();
}
/**
* Returns the default descriptor for constructors.
*/
static String defaultConstDescriptor() {
return "([Ljava/lang/Object;)V";
}
}
static class IntConstParameter extends ConstParameter {
int param;
IntConstParameter(int i) {
param = i;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addIconst(param);
return 1;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;I)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;I)V";
}
}
static class LongConstParameter extends ConstParameter {
long param;
LongConstParameter(long l) {
param = l;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addLconst(param);
return 2;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;J)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;J)V";
}
}
static class StringConstParameter extends ConstParameter {
String param;
StringConstParameter(String s) {
param = s;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addLdc(param);
return 1;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;Ljava/lang/String;)V";
}
}
}