package org.pitest.coverage.analysis;
import java.util.List;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.MethodNode;
import org.pitest.coverage.CoverageClassVisitor;
import org.pitest.mutationtest.engine.gregor.analysis.DefaultInstructionCounter;
import org.pitest.mutationtest.engine.gregor.analysis.InstructionTrackingMethodVisitor;
import sun.pitest.CodeCoverageStore;
/**
* Need to count the number of blocks in the method. Storing method as a tree
* enables a second scan by the instrumenting visitor
*
*/
public class CoverageAnalyser extends MethodNode {
private static final int MAX_SUPPORTED_LOCAL_PROBES = 15;
private final CoverageClassVisitor parent;
private final int classId;
private final MethodVisitor mv;
private final int probeOffset;
public CoverageAnalyser(final CoverageClassVisitor parent, final int classId,
final int probeOffset, final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
final String[] exceptions) {
super(Opcodes.ASM5, access, name, desc, signature, exceptions);
this.mv = mv;
this.parent = parent;
this.classId = classId;
this.probeOffset = probeOffset;
}
@Override
public void visitEnd() {
final List<Block> blocks = findRequriedProbeLocations();
this.parent.registerProbes(blocks.size());
final int blockCount = blocks.size();
CodeCoverageStore.registerMethod(this.classId, this.name, this.desc,
this.probeOffset, (this.probeOffset + blocks.size()) - 1);
// according to the jvm spec
// "There must never be an uninitialized class instance in a local variable in code protected by an exception handler"
// the code to add finally blocks used by the local variable and array based
// probe approaches is not currently
// able to meet this guarantee for constructors. Although they appear to
// work, they are rejected by the
// java 7 verifier - hence fall back to a simple but slow approach.
final DefaultInstructionCounter counter = new DefaultInstructionCounter();
if ((blockCount == 1) || this.name.equals("<init>")) {
accept(new InstructionTrackingMethodVisitor(
new SimpleBlockCoverageVisitor(blocks, counter, this.classId,
this.mv, this.access, this.name, this.desc, this.probeOffset),
counter));
} else if ((blockCount <= MAX_SUPPORTED_LOCAL_PROBES) && (blockCount >= 1)) {
accept(new InstructionTrackingMethodVisitor(
new LocalVariableCoverageMethodVisitor(blocks, counter, this.classId,
this.mv, this.access, this.name, this.desc, this.probeOffset),
counter));
} else {
// for now fall back to the naive implementation - could instead use array
// passing version
accept(new InstructionTrackingMethodVisitor(
new ArrayProbeCoverageMethodVisitor(blocks, counter, this.classId,
this.mv, this.access, this.name, this.desc, this.probeOffset),
counter));
}
}
private List<Block> findRequriedProbeLocations() {
return ControlFlowAnalyser.analyze(this);
}
}