package org.pitest.coverage.analysis; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.pitest.classinfo.ClassName; import org.pitest.classpath.CodeSource; import org.pitest.coverage.BlockLocation; import org.pitest.coverage.LineMap; import org.pitest.functional.Option; import org.pitest.mutationtest.engine.Location; import org.pitest.mutationtest.engine.MethodName; public class LineMapper implements LineMap { private final CodeSource source; public LineMapper(final CodeSource source) { this.source = source; } @Override public Map<BlockLocation, Set<Integer>> mapLines(final ClassName clazz) { final Map<BlockLocation, Set<Integer>> map = new HashMap<BlockLocation, Set<Integer>>(); final Option<byte[]> maybeBytes = this.source.fetchClassBytes(clazz); // classes generated at runtime eg by mocking frameworks // will be instrumented but not available on the classpath for (final byte[] bytes : maybeBytes) { final ClassReader cr = new ClassReader(bytes); final ClassNode classNode = new ClassNode(); cr.accept(classNode, ClassReader.EXPAND_FRAMES); for (final Object m : classNode.methods) { final MethodNode mn = (MethodNode) m; final Location l = Location.location(clazz, MethodName.fromString(mn.name), mn.desc); final List<Block> blocks = ControlFlowAnalyser.analyze(mn); for (int i = 0; i != blocks.size(); i++) { final BlockLocation bl = new BlockLocation(l, i); map.put(bl, blocks.get(i).getLines()); } } } return map; } }