/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mkstubs.stubber;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * A method visitor that generates a code stub for the visited method.
 * <p/>
 * Annotations and parameters are passed as-is.
 * All other code is replaced by the following:
 * <pre>throw new RuntimeException("stub");</pre>
 * Note that constructors rewritten this way will probably fail with the runtime bytecode
 * verifier since no call to <code>super</code> is generated.
 */
public class MethodStubber extends MethodAdapter {

    public MethodStubber(MethodVisitor mw,
            int access, String name, String desc, String signature, String[] exceptions) {
        super(mw);
    }
    
    @Override
    public void visitCode() {
        Label l0 = new Label();
        mv.visitLabel(l0);
        mv.visitLineNumber(36, l0);
        mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException");
        mv.visitInsn(Opcodes.DUP);
        mv.visitLdcInsn("stub");
        mv.visitMethodInsn(
                Opcodes.INVOKESPECIAL,          // opcode
                "java/lang/RuntimeException",   // owner
                "<init>",                       // name
                "(Ljava/lang/String;)V");       // desc
        mv.visitInsn(Opcodes.ATHROW);
        Label l1 = new Label();
        mv.visitLabel(l1);
        mv.visitLocalVariable(
                "this",                                         // name
                "Lcom/android/mkstubs/stubber/MethodStubber;",  // desc
                null,                                           // signature
                l0,                                             // label start
                l1,                                             // label end
                0);                                             // index
        mv.visitMaxs(3, 1); // maxStack, maxLocals
    }
    
    @Override
    public void visitEnd() {
        super.visitEnd();
    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        return super.visitAnnotation(desc, visible);
    }
    
    @Override
    public AnnotationVisitor visitAnnotationDefault() {
        return super.visitAnnotationDefault();
    }
 
    @Override
    public void visitAttribute(Attribute attr) {
        super.visitAttribute(attr);
    }
    
    @Override
    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
        return super.visitParameterAnnotation(parameter, desc, visible);
    }

    // -- stuff that gets skipped
    
    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        // skip
    }
    
    @Override
    public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
        // skip
    }
    
    @Override
    public void visitIincInsn(int var, int increment) {
        // skip
    }
    
    @Override
    public void visitInsn(int opcode) {
        // skip
    }
    
    @Override
    public void visitIntInsn(int opcode, int operand) {
        // skip
    }
    
    @Override
    public void visitJumpInsn(int opcode, Label label) {
        // skip
    }
    
    @Override
    public void visitLabel(Label label) {
        // skip
    }
    
    @Override
    public void visitLdcInsn(Object cst) {
        // skip
    }
    
    @Override
    public void visitLineNumber(int line, Label start) {
        // skip
    }
    
    @Override
    public void visitLocalVariable(String name, String desc, String signature,
            Label start, Label end, int index) {
        // skip
    }
    
    @Override
    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
        // skip
    }
    
    @Override
    public void visitMaxs(int maxStack, int maxLocals) {
        // skip
    }
    
    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        // skip
    }
    
    @Override
    public void visitMultiANewArrayInsn(String desc, int dims) {
        // skip
    }
    
    @Override
    public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
        // skip
    }
    
    @Override
    public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
        // skip
    }
    
    @Override
    public void visitTypeInsn(int opcode, String type) {
        // skip
    }
    
    @Override
    public void visitVarInsn(int opcode, int var) {
        // skip
    }
}
