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;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.Javac;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.compiler.CompileError;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * An instance of CtConstructor represents a constructor.
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It may represent a static constructor
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * (class initializer).  To distinguish a constructor and a class
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initializer, call <code>isClassInitializer()</code>.
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>See the super class <code>CtBehavior</code> as well since
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a number of useful methods are in <code>CtBehavior</code>.
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#getDeclaredConstructors()
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtClass#getClassInitializer()
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see CtNewConstructor
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic final class CtConstructor extends CtBehavior {
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected CtConstructor(MethodInfo minfo, CtClass declaring) {
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super(declaring, minfo);
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Creates a constructor with no constructor body.
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The created constructor
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * must be added to a class with <code>CtClass.addConstructor()</code>.
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>The created constructor does not include a constructor body,
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * which must be specified with <code>setBody()</code>.
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param declaring         the class to which the created method is added.
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param parameters        a list of the parameter types
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see CtClass#addConstructor(CtConstructor)
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see CtConstructor#setBody(String)
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see CtConstructor#setBody(CtConstructor,ClassMap)
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtConstructor(CtClass[] parameters, CtClass declaring) {
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this((MethodInfo)null, declaring);
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool cp = declaring.getClassFile2().getConstPool();
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String desc = Descriptor.ofConstructor(parameters);
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        methodInfo = new MethodInfo(cp, "<init>", desc);
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setModifiers(Modifier.PUBLIC);
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Creates a copy of a <code>CtConstructor</code> object.
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The created constructor must be
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * added to a class with <code>CtClass.addConstructor()</code>.
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>All occurrences of class names in the created constructor
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * are replaced with names specified by
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>map</code> if <code>map</code> is not <code>null</code>.
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>By default, all the occurrences of the names of the class
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * declaring <code>src</code> and the superclass are replaced
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * with the name of the class and the superclass that
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the created constructor is added to.
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This is done whichever <code>map</code> is null or not.
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * To prevent this replacement, call <code>ClassMap.fix()</code>
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * or <code>put()</code> to explicitly specify replacement.
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p><b>Note:</b> if the <code>.class</code> notation (for example,
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>String.class</code>) is included in an expression, the
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Javac compiler may produce a helper method.
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Since this constructor never
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * copies this helper method, the programmers have the responsiblity of
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * copying it.  Otherwise, use <code>Class.forName()</code> in the
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * expression.
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src       the source method.
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param declaring    the class to which the created method is added.
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param map       the hashtable associating original class names
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  with substituted names.
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  It can be <code>null</code>.
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see CtClass#addConstructor(CtConstructor)
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see ClassMap#fix(String)
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map)
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this((MethodInfo)null, declaring);
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        copy(src, true, map);
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if this object represents a constructor.
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isConstructor() {
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return methodInfo.isConstructor();
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if this object represents a static initializer.
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isClassInitializer() {
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return methodInfo.isStaticInitializer();
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the constructor name followed by parameter types
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * such as <code>javassist.CtConstructor(CtClass[],CtClass)</code>.
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @since 3.5
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getLongName() {
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return getDeclaringClass().getName()
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal               + (isConstructor() ? Descriptor.toString(getSignature())
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  : ("." + MethodInfo.nameClinit + "()"));
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Obtains the name of this constructor.
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It is the same as the simple name of the class declaring this
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * constructor.  If this object represents a class initializer,
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * then this method returns <code>"&lt;clinit&gt;"</code>.
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String getName() {
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (methodInfo.isStaticInitializer())
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return MethodInfo.nameClinit;
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return declaringClass.getSimpleName();
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if the constructor (or static initializer)
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is the default one.  This method returns true if the constructor
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * takes some arguments but it does not perform anything except
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * calling <code>super()</code> (the no-argument constructor of
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the super class).
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isEmpty() {
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute ca = getMethodInfo2().getCodeAttribute();
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (ca == null)
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;       // native or abstract??
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                // they are not allowed, though.
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ConstPool cp = ca.getConstPool();
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeIterator it = ca.iterator();
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int pos, desc;
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int op0 = it.byteAt(it.next());
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return op0 == Opcode.RETURN     // empty static initializer
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                || (op0 == Opcode.ALOAD_0
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && (desc = cp.isConstructor(getSuperclassName(),
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                                it.u16bitAt(pos + 1))) != 0
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && "()V".equals(cp.getUtf8Info(desc))
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && it.byteAt(it.next()) == Opcode.RETURN
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    && !it.hasNext());
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadBytecode e) {}
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return false;
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String getSuperclassName() {
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassFile cf = declaringClass.getClassFile2();
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return cf.getSuperclass();
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if this constructor calls a constructor
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * of the super class.  This method returns false if it
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * calls another constructor of this class by <code>this()</code>.
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean callsSuper() throws CannotCompileException {
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute codeAttr = methodInfo.getCodeAttribute();
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (codeAttr != null) {
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CodeIterator it = codeAttr.iterator();
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int index = it.skipSuperConstructor();
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return index >= 0;
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (BadBytecode e) {
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                throw new CannotCompileException(e);
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return false;
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets a constructor body.
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src       the source code representing the constructor body.
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  It must be a single statement or block.
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  If it is <code>null</code>, the substituted
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  constructor body does nothing except calling
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  <code>super()</code>.
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setBody(String src) throws CannotCompileException {
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (src == null)
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (isClassInitializer())
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                src = ";";
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                src = "super();";
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super.setBody(src);
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Copies a constructor body from another constructor.
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>All occurrences of the class names in the copied body
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * are replaced with the names specified by
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <code>map</code> if <code>map</code> is not <code>null</code>.
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src       the method that the body is copied from.
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param map       the hashtable associating original class names
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  with substituted names.
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  It can be <code>null</code>.
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setBody(CtConstructor src, ClassMap map)
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        setBody0(src.declaringClass, src.methodInfo,
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                 declaringClass, methodInfo, map);
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Inserts bytecode just after another constructor in the super class
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * or this class is called.
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It does not work if this object represents a class initializer.
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src       the source code representing the inserted bytecode.
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  It must be a single statement or block.
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void insertBeforeBody(String src) throws CannotCompileException {
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtClass cc = declaringClass;
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cc.checkModify();
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (isClassInitializer())
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException("class initializer");
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeAttribute ca = methodInfo.getCodeAttribute();
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeIterator iterator = ca.iterator();
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Bytecode b = new Bytecode(methodInfo.getConstPool(),
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                  ca.getMaxStack(), ca.getMaxLocals());
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        b.setStackDepth(ca.getMaxStack());
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Javac jv = new Javac(b, cc);
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jv.recordParams(getParameterTypes(), false);
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            jv.compileStmnt(src);
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ca.setMaxStack(b.getMaxStack());
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ca.setMaxLocals(b.getMaxLocals());
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            iterator.skipConstructor();
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int pos = iterator.insertEx(b.get());
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            iterator.insert(b.getExceptionTable(), pos);
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NotFoundException e) {
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (CompileError e) {
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadBytecode e) {
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /* This method is called by addCatch() in CtBehavior.
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * super() and this() must not be in a try statement.
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeIterator ci = ca.iterator();
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ci.skipConstructor();
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return ci.next();
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadBytecode e) {
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Makes a copy of this constructor and converts it into a method.
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The signature of the mehtod is the same as the that of this constructor.
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The return type is <code>void</code>.  The resulting method must be
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * appended to the class specified by <code>declaring</code>.
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If this constructor is a static initializer, the resulting method takes
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * no parameter.
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>An occurrence of another constructor call <code>this()</code>
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * or a super constructor call <code>super()</code> is
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * eliminated from the resulting method.
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>The immediate super class of the class declaring this constructor
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * must be also a super class of the class declaring the resulting method.
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the constructor accesses a field, the class declaring the resulting method
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * must also declare a field with the same name and type.
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param name              the name of the resulting method.
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param declaring         the class declaring the resulting method.
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtMethod toMethod(String name, CtClass declaring)
31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return toMethod(name, declaring, null);
31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Makes a copy of this constructor and converts it into a method.
32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The signature of the method is the same as the that of this constructor.
32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * The return type is <code>void</code>.  The resulting method must be
32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * appended to the class specified by <code>declaring</code>.
32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If this constructor is a static initializer, the resulting method takes
32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * no parameter.
32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>An occurrence of another constructor call <code>this()</code>
32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * or a super constructor call <code>super()</code> is
32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * eliminated from the resulting method.
33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>The immediate super class of the class declaring this constructor
33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * must be also a super class of the class declaring the resulting method
33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * (this is obviously true if the second parameter <code>declaring</code> is
33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the same as the class declaring this constructor).
33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the constructor accesses a field, the class declaring the resulting method
33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * must also declare a field with the same name and type.
33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param name              the name of the resulting method.
33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param declaring         the class declaring the resulting method.
34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          It is normally the same as the class declaring this
34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                          constructor.
34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param map       the hash table associating original class names
34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  with substituted names.  The original class names will be
34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  replaced while making a copy.
34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *                  <code>map</code> can be <code>null</code>.
34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtMethod toMethod(String name, CtClass declaring, ClassMap map)
34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CtMethod method = new CtMethod(null, declaring);
35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        method.copy(this, false, map);
35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (isConstructor()) {
35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            MethodInfo minfo = method.getMethodInfo2();
35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CodeAttribute ca = minfo.getCodeAttribute();
35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (ca != null) {
35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                removeConsCall(ca);
35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                try {
35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    methodInfo.rebuildStackMapIf6(declaring.getClassPool(),
35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                                  declaring.getClassFile2());
36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                catch (BadBytecode e) {
36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    throw new CannotCompileException(e);
36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        method.setName(name);
36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return method;
36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static void removeConsCall(CodeAttribute ca)
37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        CodeIterator iterator = ca.iterator();
37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int pos = iterator.skipConstructor();
37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (pos >= 0) {
37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int mref = iterator.u16bitAt(pos + 1);
37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                String desc = ca.getConstPool().getMethodrefType(mref);
38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                int num = Descriptor.numOfParameters(desc) + 1;
38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (num > 3)
38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    pos = iterator.insertGapAt(pos, num - 3, false).position;
38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                iterator.writeByte(Opcode.POP, pos++);  // this
38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                iterator.writeByte(Opcode.NOP, pos);
38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                iterator.writeByte(Opcode.NOP, pos + 1);
38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Descriptor.Iterator it = new Descriptor.Iterator(desc);
38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                while (true) {
38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    it.next();
39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (it.isParameter())
39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        iterator.writeByte(it.is2byte() ? Opcode.POP2 : Opcode.POP,
39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                           pos++);
39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    else
39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        break;
39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (BadBytecode e) {
39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
403