org.mutabilitydetector.checkers.settermethod.AssignmentGuard.java Source code

Java tutorial

Introduction

Here is the source code for org.mutabilitydetector.checkers.settermethod.AssignmentGuard.java

Source

/**
 * 
 */
package org.mutabilitydetector.checkers.settermethod;

/*
 * #%L
 * MutabilityDetector
 * %%
 * Copyright (C) 2008 - 2014 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.
 * #L%
 */

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.objectweb.asm.tree.AbstractInsnNode.*;

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

import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;

import org.objectweb.asm.tree.*;

/**
 * An Assignment Guard is the condition check which decides whether or
 * not to initialise a certain lazy variable.
 * 
 * @author Juergen Fickel (jufickel@htwg-konstanz.de)
 * @version 07.03.2013
 */
final class AssignmentGuard implements JumpInsn {

    /**
     * Builder for instances of {@link AssignmentGuard}.
     */
    @NotThreadSafe
    public static final class Builder {

        private final JumpInsn jumpInstruction;
        private final ArrayList<AbstractInsnNode> predecessorInstructions;

        public Builder(final JumpInsn theJumpInstruction) {
            jumpInstruction = theJumpInstruction;
            predecessorInstructions = new ArrayList<AbstractInsnNode>();
        }

        public void addPredecessorInstruction(final AbstractInsnNode predecessor) {
            predecessorInstructions.add(predecessor);
        }

        public AssignmentGuard build() {
            predecessorInstructions.trimToSize();
            return AssignmentGuard.newInstance(jumpInstruction, predecessorInstructions);
        }

        @Override
        public String toString() {
            final StringBuilder b = new StringBuilder();
            b.append(getDeclaringClassPrefix()).append(getClass().getSimpleName());
            b.append(" [jumpInstruction=").append(jumpInstruction);
            b.append(", predecessorInstructions=").append(predecessorInstructions).append("]");
            return b.toString();
        }

        private String getDeclaringClassPrefix() {
            final String result;
            final Class<?> superclass = getClass().getDeclaringClass();
            if (null != superclass) {
                final StringBuilder b = new StringBuilder();
                b.append(superclass.getSimpleName()).append(".");
                result = b.toString();
            } else {
                result = "";
            }
            return result;
        }

    } // class AssignmentGuardBuilder

    @Immutable
    private static final class InstructionNodesHashCodeCalculator {

        private static final byte INITIAL_RESULT = 1;

        private final int prime;

        public InstructionNodesHashCodeCalculator(final int thePrime) {
            prime = thePrime;
        }

        public int hashCode(final AbstractInsnNode insn) {
            final int result;
            final int nodeType = insn.getType();
            if (FIELD_INSN == nodeType) {
                result = hashCode((FieldInsnNode) insn);
            } else if (VAR_INSN == nodeType) {
                result = hashCode((VarInsnNode) insn);
            } else if (INSN == nodeType) {
                result = hashCode((InsnNode) insn);
            } else if (INT_INSN == nodeType) {
                result = hashCode((IntInsnNode) insn);
            } else if (INVOKE_DYNAMIC_INSN == nodeType) {
                result = hashCode((InvokeDynamicInsnNode) insn);
            } else if (JUMP_INSN == nodeType) {
                result = hashCode((JumpInsnNode) insn);
            } else if (LABEL == nodeType) {
                result = hashCode((LabelNode) insn);
            } else if (LDC_INSN == nodeType) {
                result = hashCode((LdcInsnNode) insn);
            } else if (LINE == nodeType) {
                result = hashCode((LineNumberNode) insn);
            } else if (METHOD_INSN == nodeType) {
                result = hashCode((MethodInsnNode) insn);
            } else if (IINC_INSN == nodeType) {
                result = hashCode((IincInsnNode) insn);
            } else if (LOOKUPSWITCH_INSN == nodeType) {
                result = hashCode((LookupSwitchInsnNode) insn);
            } else if (FRAME == nodeType) {
                result = hashCode((FrameNode) insn);
            } else if (TYPE_INSN == nodeType) {
                result = hashCode((TypeInsnNode) insn);
            } else if (MULTIANEWARRAY_INSN == nodeType) {
                result = hashCode((MultiANewArrayInsnNode) insn);
            } else if (TABLESWITCH_INSN == nodeType) {
                result = hashCode((TableSwitchInsnNode) insn);
            } else {
                result = insn.hashCode();
            }
            return hashCode(result, insn.getOpcode());
        }

        private int hashCode(final FieldInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.desc.hashCode());
            result = hashCode(result, insn.name.hashCode());
            result = hashCode(result, insn.owner.hashCode());
            return result;
        }

        private final int hashCode(final int preliminaryResult, final int hashCode) {
            return prime * preliminaryResult + hashCode;
        }

        private int hashCode(final VarInsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.var);
        }

        private int hashCode(final InsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.hashCode());
        }

        private int hashCode(final IntInsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.operand);
        }

        private int hashCode(final InvokeDynamicInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.name.hashCode());
            result = hashCode(result, insn.desc.hashCode());
            result = hashCode(result, insn.bsm.hashCode());
            result = hashCode(result, insn.hashCode());
            return result;
        }

        private int hashCode(final JumpInsnNode insn) {
            return hashCode(INITIAL_RESULT, 0);
        }

        private int hashCode(final LabelNode insn) {
            return hashCode(INITIAL_RESULT, 0);
        }

        private int hashCode(final LdcInsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.cst.hashCode());
        }

        private int hashCode(final LineNumberNode insn) {
            return hashCode(INITIAL_RESULT, 0);
        }

        private int hashCode(final MethodInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.desc.hashCode());
            result = hashCode(result, insn.name.hashCode());
            result = hashCode(result, insn.owner.hashCode());
            return result;
        }

        private int hashCode(final IincInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.var);
            result = hashCode(result, insn.incr);
            return result;
        }

        private int hashCode(final LookupSwitchInsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.keys.hashCode());
        }

        private int hashCode(final FrameNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.local.hashCode());
            result = hashCode(result, insn.stack.hashCode());
            return result;
        }

        private int hashCode(final TypeInsnNode insn) {
            return hashCode(INITIAL_RESULT, insn.desc.hashCode());
        }

        private int hashCode(final MultiANewArrayInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.dims);
            result = hashCode(result, insn.desc.hashCode());
            return result;
        }

        private int hashCode(final TableSwitchInsnNode insn) {
            int result = INITIAL_RESULT;
            result = hashCode(result, insn.min);
            result = hashCode(result, insn.max);
            return result;
        }

    } // class InstructionNodeHashCodeCalculator

    @Immutable
    private static final class InstructionNodesComparator {

        public boolean equals(final FieldInsnNode f1, final FieldInsnNode f2) {
            return f1.desc.equals(f2.desc) && f1.name.equals(f2.name) && f1.owner.equals(f2.owner);
        }

        public boolean equals(final VarInsnNode insnThis, final VarInsnNode insnOther) {
            return insnThis.var == insnOther.var;
        }

        public boolean equals(final InsnNode insnThis, final InsnNode insnOther) {
            return true;
        }

        public boolean equals(final IntInsnNode insnThis, final IntInsnNode insnOther) {
            return insnThis.operand == insnOther.operand;
        }

        public boolean equals(final InvokeDynamicInsnNode i1, final InvokeDynamicInsnNode i2) {
            return i1.name.equals(i2.name) && i1.desc.equals(i2.desc) && i1.bsm.equals(i2.bsm)
                    && Arrays.equals(i1.bsmArgs, i2.bsmArgs);
        }

        public boolean equals(final JumpInsnNode insnThis, final JumpInsnNode insnOther) {
            return true;
        }

        public boolean equals(final LabelNode insnThis, final LabelNode insnOther) {
            return true;
        }

        public boolean equals(final LdcInsnNode insnThis, final LdcInsnNode insnOther) {
            return insnThis.cst.equals(insnOther.cst);
        }

        public boolean equals(final LineNumberNode insnThis, final LineNumberNode insnOther) {
            return true;
        }

        public boolean equals(final MethodInsnNode m1, final MethodInsnNode m2) {
            return m1.desc.equals(m2.name) && m1.name.equals(m2.name) && m1.owner.equals(m2.owner);
        }

        public boolean equals(final IincInsnNode i1, final IincInsnNode i2) {
            return i1.var == i2.var && i1.incr == i2.incr;
        }

        public boolean equals(final LookupSwitchInsnNode l1, final LookupSwitchInsnNode l2) {
            return l1.keys.equals(l2.keys);
        }

        public boolean equals(final FrameNode f1, final FrameNode f2) {
            return f1.local.equals(f2.local) && f1.stack.equals(f2.stack);
        }

        public boolean equals(final TypeInsnNode t1, final TypeInsnNode t2) {
            return t1.desc.equals(t2.desc);
        }

        public boolean equals(final MultiANewArrayInsnNode m1, final MultiANewArrayInsnNode m2) {
            return m1.desc.equals(m2.desc) && m1.dims == m2.dims;
        }

        public boolean equals(final TableSwitchInsnNode t1, final TableSwitchInsnNode t2) {
            return t1.min == t2.min && t1.max == t2.max;
        }

    } // class InstructionNodesComparator

    private final JumpInsn delegationTarget;
    private final List<AbstractInsnNode> predecessorInstructions;

    private AssignmentGuard(final JumpInsn theDelegationTarget,
            final List<AbstractInsnNode> thePredecessorInstructions) {
        delegationTarget = theDelegationTarget;
        predecessorInstructions = thePredecessorInstructions;
    }

    public static AssignmentGuard newInstance(final JumpInsn delegationTarget,
            final List<AbstractInsnNode> predecessorInstructions) {
        validateArguments(delegationTarget, predecessorInstructions);
        return new AssignmentGuard(delegationTarget, predecessorInstructions);
    }

    private static void validateArguments(final JumpInsn delegationTarget,
            final List<AbstractInsnNode> predecessorInstructions) {
        final String msg = "Argument '%s' must not be %s!";
        checkNotNull(delegationTarget, msg, "delegationTarget", "null");
        checkNotNull(predecessorInstructions, msg, "predecessorInstructions", "null");
        checkArgument(!predecessorInstructions.isEmpty(), msg, "predecessorInstructions", "empty");
    }

    @Override
    public JumpInsnNode getJumpInsnNode() {
        return delegationTarget.getJumpInsnNode();
    }

    @Override
    public int getIndexWithinBlock() {
        return delegationTarget.getIndexWithinBlock();
    }

    @Override
    public int getIndexWithinMethod() {
        return delegationTarget.getIndexWithinMethod();
    }

    @Override
    public Opcode getOpcode() {
        return delegationTarget.getOpcode();
    }

    @Override
    public boolean isAssignmentGuard() {
        return true;
    }

    @Override
    public int compareTo(final JumpInsn o) {
        return delegationTarget.compareTo(o);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        final JumpInsnNode jumpInsnNode = getJumpInsnNode();
        result = prime * result + jumpInsnNode.getOpcode();
        final InstructionNodesHashCodeCalculator hcc = new InstructionNodesHashCodeCalculator(prime);
        for (final AbstractInsnNode predecessor : predecessorInstructions) {
            final int hashCodeOfPredecessor = hcc.hashCode(predecessor);
            result = prime * result + hashCodeOfPredecessor;
        }
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof AssignmentGuard)) {
            return false;
        }
        final AssignmentGuard other = (AssignmentGuard) obj;
        final JumpInsnNode jumpInsnNodeThis = delegationTarget.getJumpInsnNode();
        final JumpInsnNode jumpInsnNodeOther = other.getJumpInsnNode();
        if (jumpInsnNodeThis.getOpcode() != jumpInsnNodeOther.getOpcode()) {
            return false;
        }
        if (predecessorInstructions.size() != other.predecessorInstructions.size()) {
            return false;
        }
        final InstructionNodesComparator inc = new InstructionNodesComparator();
        for (int i = 0; i < predecessorInstructions.size(); i++) {
            final AbstractInsnNode insnsThis = predecessorInstructions.get(i);
            final AbstractInsnNode insnsOther = other.predecessorInstructions.get(i);
            if (insnsThis.getOpcode() != insnsOther.getOpcode()) {
                return false;
            }
            if (instructionsAreUnequal(insnsThis, insnsOther, inc)) {
                return false;
            }
        }
        return true;
    }

    private static boolean instructionsAreUnequal(final AbstractInsnNode insnThis, final AbstractInsnNode insnOther,
            final InstructionNodesComparator inc) {
        final int nodeType = insnThis.getType();
        final boolean result;
        if (FIELD_INSN == nodeType) {
            result = inc.equals((FieldInsnNode) insnThis, (FieldInsnNode) insnOther);
        } else if (VAR_INSN == nodeType) {
            result = inc.equals((VarInsnNode) insnThis, (VarInsnNode) insnOther);
        } else if (INSN == nodeType) {
            result = inc.equals((InsnNode) insnThis, (InsnNode) insnOther);
        } else if (INT_INSN == nodeType) {
            result = inc.equals((IntInsnNode) insnThis, (IntInsnNode) insnOther);
        } else if (INVOKE_DYNAMIC_INSN == nodeType) {
            result = inc.equals((InvokeDynamicInsnNode) insnThis, (InvokeDynamicInsnNode) insnOther);
        } else if (JUMP_INSN == nodeType) {
            result = inc.equals((JumpInsnNode) insnThis, (JumpInsnNode) insnOther);
        } else if (LABEL == nodeType) {
            result = inc.equals((LabelNode) insnThis, (LabelNode) insnOther);
        } else if (LDC_INSN == nodeType) {
            result = inc.equals((LdcInsnNode) insnThis, (LdcInsnNode) insnOther);
        } else if (LINE == nodeType) {
            result = inc.equals((LineNumberNode) insnThis, (LineNumberNode) insnOther);
        } else if (METHOD_INSN == nodeType) {
            result = inc.equals((MethodInsnNode) insnThis, (MethodInsnNode) insnOther);
        } else if (IINC_INSN == nodeType) {
            result = inc.equals((IincInsnNode) insnThis, (IincInsnNode) insnOther);
        } else if (LOOKUPSWITCH_INSN == nodeType) {
            result = inc.equals((LookupSwitchInsnNode) insnThis, (LookupSwitchInsnNode) insnOther);
        } else if (FRAME == nodeType) {
            result = inc.equals((FrameNode) insnThis, (FrameNode) insnOther);
        } else if (TYPE_INSN == nodeType) {
            result = inc.equals((TypeInsnNode) insnThis, (TypeInsnNode) insnOther);
        } else if (MULTIANEWARRAY_INSN == nodeType) {
            result = inc.equals((MultiANewArrayInsnNode) insnThis, (MultiANewArrayInsnNode) insnOther);
        } else if (TABLESWITCH_INSN == nodeType) {
            result = inc.equals((TableSwitchInsnNode) insnThis, (TableSwitchInsnNode) insnOther);
        } else {
            result = false;
        }
        return !result;
    }

    @Override
    public String toString() {
        final StringBuilder b = new StringBuilder();
        b.append(getClass().getSimpleName()).append(" [delegationTarget=").append(delegationTarget);
        b.append(", predecessorInstructions=").append(predecessorInstructions).append("]");
        return b.toString();
    }

}