/* 
 * Mutability Detector
 *
 * Copyright 2009 Graham Allan
 * 
 * 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 org.mutabilitydetector.checkers;

import java.util.ArrayList;
import java.util.List;

import org.mutabilitydetector.asmoverride.CustomClassLoadingSimpleVerifier;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Analyzer;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Frame;

public abstract class FieldAssignmentVisitor extends MethodNode {

    protected List<FieldInsnNode> fieldAssignments = new ArrayList<FieldInsnNode>();
    protected final String owner;

    public FieldAssignmentVisitor(String owner,
            int access,
            String name,
            String desc,
            String signature,
            String[] exceptions) {
        super(access, name, desc, signature, exceptions);
        this.owner = owner;
    }

    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        super.visitFieldInsn(opcode, owner, name, desc);
        if (opcode == Opcodes.PUTFIELD) {
            fieldAssignments.add((FieldInsnNode) instructions.getLast());
        }

    }

    @Override
    public void visitEnd() {
        super.visitEnd();

        if (fieldAssignments.isEmpty()) { return; }

        Analyzer a = new Analyzer(new CustomClassLoadingSimpleVerifier());
        Frame[] frames;
        try {
            frames = a.analyze(owner, this);

            for (FieldInsnNode fieldInsnNode : fieldAssignments) {
                Frame assignmentFrame = frames[instructions.indexOf(fieldInsnNode)];
                int stackSlot = assignmentFrame.getStackSize() - 1;
                BasicValue stackValue = (BasicValue) assignmentFrame.getStack(stackSlot);
                visitFieldAssignmentFrame(assignmentFrame, fieldInsnNode, stackValue);
            }
        } catch (AnalyzerException forwarded) {
            throw new RuntimeException(forwarded);
        }
    }

    /**
     * 
     * At the end of a method, the frames are analysed to be able to inspect the state of the stack when the field is
     * assigned. This method is called, giving the frame at the time of the assignment, as well as the instruction node.
     * 
     * @param assignmentFrame
     * @param fieldInsnNode
     */
    abstract protected void visitFieldAssignmentFrame(Frame assignmentFrame,
            FieldInsnNode fieldInsnNode,
            BasicValue stackValue);

    protected boolean isInvalidStackValue(BasicValue stackValue) {
        return stackValue == null || "Lnull;".equals(stackValue.getType().toString());
    }

    protected BasicValue getStackValue(Frame assignmentFrame) {
        int stackSlot = assignmentFrame.getStackSize() - 1;
        BasicValue stackValue = (BasicValue) assignmentFrame.getStack(stackSlot);
        return stackValue;
    }
}

@@ -1862,36 +1862,474 @@
       %7D%0A%0A    %7D%0A%0A
-    
+%09/**%0A%09 * %0A%09 * At the end of a method, the frames are analysed to be able to inspect%0A%09 * the state of the stack when the field is assigned. This method is%0A%09 * called, giving the frame at the time of the assignment, as well as%0A%09 * the instruction node.%0A%09 * %0A%09 * @param assignmentFrame%0A%09 * @param fieldInsnNode%0A%09 */%0A%09abstract protected void visitFieldAssignmentFrame(Frame assignmentFrame, FieldInsnNode fieldInsnNode, BasicValue stackValue);%0A%0A%09
 @Override%0A    pu
@@ -3121,492 +3121,8 @@
  %7D%0A%0A
-    /**%0A     * %0A     * At the end of a method, the frames are analysed to be able to inspect the state of the stack when the field is%0A     * assigned. This method is called, giving the frame at the time of the assignment, as well as the instruction node.%0A     * %0A     * @param assignmentFrame%0A     * @param fieldInsnNode%0A     */%0A    abstract protected void visitFieldAssignmentFrame(Frame assignmentFrame,%0A            FieldInsnNode fieldInsnNode,%0A            BasicValue stackValue);%0A%0A
     

Inline variable.