package org.coldswap.util;

/**
 * (C) Copyright 2013 Faur Ioan-Aurel.
 * <p/>
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 * <p/>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * <p/>
 * Contributors:
 * faur
 * <p/>
 * Created at:
 * 8:39 PM       5/14/13
 */

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;

/**
 * Helper class for extracting method return type, method params type, etc...
 */
public class MethodUtil {

    public static Type getReturnType(MethodNode methodNode) {
        String methodDesc = methodNode.desc;
        // get 2 strings one containing the var params and
        // the other the return type
        String[] descs = methodDesc.split("\\)");
        return Type.getReturnType(descs[1]);
    }

    public static Type[] getParamsType(MethodNode methodNode) {
        String methodDesc = methodNode.desc;
        // get 2 strings one containing the var params and
        // the other the return type
        String[] descs = methodDesc.split("\\)");
        // get a list of params that this method has
        String[] paramType = null;
        if (!descs[0].equals("(")) {
            paramType = descs[0].substring(1).split(";");
            // append ";"
            for (int i = 0; i < paramType.length; i++) {
                paramType[i] = paramType[i] + ";";
            }
        }
        Type[] toRet = new Type[0];
        if (paramType != null) {
            toRet = new Type[paramType.length];
            for (int i = 0; i < toRet.length; i++) {
                toRet[i] = Type.getType(paramType[i]);
            }
        }
        return toRet;
    }

    public static Type classToType(Class<?> aClass) {
        return Type.getType(aClass);
    }

    public static Type[] classToType(Class<?>[] classes) {
        Type[] toRet = new Type[classes.length];
        for (int i = 0; i < toRet.length; i++) {
            toRet[i] = classToType(classes[i]);
        }
        return toRet;
    }

    public static MethodNode createHelperMethod(String className) {
        int acc = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS;
        String methodName = TransformerNameGenerator.getObjectMethodName(className);
        MethodNode mn = new MethodNode(acc, methodName, "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
        InsnList insnList = mn.instructions;
        insnList.add(new LabelNode());
        insnList.add(new InsnNode(Opcodes.ACONST_NULL));
        insnList.add(new InsnNode(Opcodes.ARETURN));
        insnList.add(new LabelNode());
        return mn;

    }

    public static MethodNode createObjectHelperMethod(String className, int counter) {
        int acc = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS;
        String methodName = TransformerNameGenerator.getObjectMethodNameWithCounter(className, counter);
        MethodNode mn = new MethodNode(acc, methodName, "([Ljava/lang/Object;)Ljava/lang/Object;", null, null);
        InsnList insnList = mn.instructions;
        LabelNode l0 = new LabelNode();
        insnList.add(l0);
        insnList.add(new InsnNode(Opcodes.ACONST_NULL));
        insnList.add(new InsnNode(Opcodes.ARETURN));
        LabelNode l1 = new LabelNode();
        insnList.add(l1);
        String classLiteral = "L" + className + ";";
        mn.localVariables.add(new LocalVariableNode("this", classLiteral, null, l0, l1, 0));
        mn.localVariables.add(new LocalVariableNode("args", "[Ljava/lang/Object;", null, l0, l1, 1));
        mn.maxStack = 1;
        mn.maxLocals = 2;
        return mn;

    }

    public static MethodNode createIntHelperMethod(String className, int counter) {
        int acc = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS;
        String methodName = TransformerNameGenerator.getIntMethodNameWithCounter(className, counter);
        MethodNode mn = new MethodNode(acc, methodName, "(I)Ljava/lang/Object;", null, null);
        InsnList insnList = mn.instructions;
        LabelNode l0 = new LabelNode();
        insnList.add(l0);
        insnList.add(new InsnNode(Opcodes.ACONST_NULL));
        insnList.add(new InsnNode(Opcodes.ARETURN));
        LabelNode l1 = new LabelNode();
        insnList.add(l1);
        String classLiteral = "L" + className + ";";
        mn.localVariables.add(new LocalVariableNode("this", classLiteral, null, l0, l1, 0));
        mn.localVariables.add(new LocalVariableNode("arg", "I", null, l0, l1, 1));
        mn.maxStack = 1;
        mn.maxLocals = 2;
        return mn;
    }

    public static int getRetOpcodeToReplace(Type retType) {
        String retDesc = retType.getDescriptor();
        int opcode = Opcodes.IRETURN;
        if ("Z".equals(retDesc)) {
            opcode = Opcodes.IRETURN;
        } else if ("B".equals(retDesc)) {
            opcode = Opcodes.IRETURN;
        } else if ("C".equals(retDesc)) {
            opcode = Opcodes.IRETURN;
        } else if ("S".equals(retDesc)) {
            opcode = Opcodes.IRETURN;
        } else if ("I".equals(retDesc)) {
            opcode = Opcodes.IRETURN;
        } else if ("J".equals(retDesc)) {
            opcode = Opcodes.LRETURN;
        } else if ("F".equals(retDesc)) {
            opcode = Opcodes.FRETURN;
        } else if ("D".equals(retDesc)) {
            opcode = Opcodes.DRETURN;
        }
        return opcode;
    }
}

@@ -1669,17 +1669,48 @@
 pend %22;%22
+ if param is not primitive type
 %0A
-
         
@@ -1750,32 +1750,85 @@
 .length; i++) %7B%0A
+                if (paramType%5Bi%5D.length() %3E 1) %7B%0A    
                 
@@ -1854,32 +1854,50 @@
 mType%5Bi%5D + %22;%22;%0A
+                %7D%0A
             %7D%0A  
@@ -2487,32 +2487,32 @@
 %5Bi%5D);%0A        %7D%0A
+
         return t
@@ -2528,611 +2528,8 @@
  %7D%0A%0A
-    public static MethodNode createHelperMethod(String className) %7B%0A        int acc = Opcodes.ACC_PUBLIC %7C Opcodes.ACC_VARARGS;%0A        String methodName = TransformerNameGenerator.getObjectMethodName(className);%0A        MethodNode mn = new MethodNode(acc, methodName, %22(Ljava/lang/String;%5BLjava/lang/Object;)Ljava/lang/Object;%22, null, null);%0A        InsnList insnList = mn.instructions;%0A        insnList.add(new LabelNode());%0A        insnList.add(new InsnNode(Opcodes.ACONST_NULL));%0A        insnList.add(new InsnNode(Opcodes.ARETURN));%0A        insnList.add(new LabelNode());%0A        return mn;%0A%0A    %7D%0A%0A
     

Fix problems with basic primitives as method arguments.