de.unisb.cs.st.javalanche.mutation.bytecodeMutations.removeSystemExit.RemoveSystemExitMethodNode.java Source code

Java tutorial

Introduction

Here is the source code for de.unisb.cs.st.javalanche.mutation.bytecodeMutations.removeSystemExit.RemoveSystemExitMethodNode.java

Source

/*
* Copyright (C) 2011 Saarland University
* 
* This file is part of Javalanche.
* 
* Javalanche is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* Javalanche 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 Public License for more details.
* 
* You should have received a copy of the GNU Lesser Public License
* along with Javalanche.  If not, see <http://www.gnu.org/licenses/>.
*/
package de.unisb.cs.st.javalanche.mutation.bytecodeMutations.removeSystemExit;

import java.util.Iterator;

import org.apache.log4j.Logger;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import de.unisb.cs.st.javalanche.mutation.bytecodeMutations.MutationMarker;

/**
 * Removes calls to {@link System}.exit and replaces them with a {@link RuntimeException}.
 * 
 * TODO Maybe this can be rewritten to use the core API instead of the tree API of ASM.
 * @author david.schuler
 *
 */
public class RemoveSystemExitMethodNode extends MethodAdapter {
    private static Logger logger = Logger.getLogger(RemoveSystemExitMethodNode.class);

    private MethodVisitor next;

    public RemoveSystemExitMethodNode(int access, String name, String desc, String signature, String[] exceptions,
            MethodVisitor mv) {
        super(new MethodNode(access, name, desc, signature, exceptions));
        next = mv;
    }

    @SuppressWarnings("unchecked")
    // Call to pre-1.5 Code
    @Override
    public void visitEnd() {
        MethodNode mn = (MethodNode) mv;
        InsnList insns = mn.instructions;
        Iterator i = insns.iterator();
        AbstractInsnNode prev = null;
        InsnList newInstrucionList = new InsnList();
        while (i.hasNext()) {
            boolean addInstruction = true;
            AbstractInsnNode i1 = (AbstractInsnNode) i.next();
            if (i1 instanceof MethodInsnNode) {
                MethodInsnNode methotInsnNode = (MethodInsnNode) i1;
                if (methotInsnNode.name.equals("exit") && methotInsnNode.owner.equals("java/lang/System")) {
                    logger.info("Replacing System.exit ");
                    newInstrucionList.remove(prev);
                    // insns.remove(i1);
                    InsnList il = new InsnList();
                    Label mutationStartLabel = new Label();
                    mutationStartLabel.info = new MutationMarker(true);

                    il.add(new LabelNode(mutationStartLabel));
                    il.add(new TypeInsnNode(Opcodes.NEW, "java/lang/RuntimeException"));
                    il.add(new InsnNode(Opcodes.DUP));
                    il.add(new LdcInsnNode("Replaced System.exit()"));
                    il.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException", "<init>",
                            "(Ljava/lang/String;)V"));
                    il.add(new InsnNode(Opcodes.ATHROW));

                    Label mutationEndLabel = new Label();
                    mutationEndLabel.info = new MutationMarker(false);
                    il.add(new LabelNode(mutationEndLabel));
                    newInstrucionList.add(il);
                    addInstruction = false;
                }
            }
            if (addInstruction) {
                try {
                    insns.remove(i1);
                    newInstrucionList.add(i1);
                } catch (Exception e) {
                    logger.error(e);
                }

            }
            prev = i1;
        }
        mn.instructions = newInstrucionList;
        mn.accept(next);
    }
}