Read CharacterRangeTableAttribute during analysis
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java index 623a1b6..29a0807 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
@@ -27,7 +27,9 @@ import org.jacoco.core.internal.analysis.ClassAnalyzer; import org.jacoco.core.internal.analysis.StringPool; import org.jacoco.core.internal.data.CRC64; +import org.jacoco.core.internal.flow.CharacterRangeTableAttribute; import org.jacoco.core.internal.flow.ClassProbesAdapter; +import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -104,7 +106,7 @@ public void analyzeClass(final ClassReader reader) { final ClassVisitor visitor = createAnalyzingVisitor( CRC64.checksum(reader.b), reader.getClassName()); - reader.accept(visitor, 0); + reader.accept(visitor, new Attribute[]{new CharacterRangeTableAttribute()}, 0); } /**
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index 08deb5b..cb873ba 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
@@ -17,10 +17,12 @@ import org.jacoco.core.analysis.ICounter; import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.analysis.ISourceNode; +import org.jacoco.core.internal.flow.CharacterRangeTableAttribute; import org.jacoco.core.internal.flow.IFrame; import org.jacoco.core.internal.flow.Instruction; import org.jacoco.core.internal.flow.LabelInfo; import org.jacoco.core.internal.flow.MethodProbesVisitor; +import org.objectweb.asm.Attribute; import org.objectweb.asm.Handle; import org.objectweb.asm.Label; @@ -95,6 +97,19 @@ } @Override + public void visitAttribute(Attribute attr) { + if (attr instanceof CharacterRangeTableAttribute) { + CharacterRangeTableAttribute characterRangeTableAttribute = (CharacterRangeTableAttribute) attr; + for (CharacterRangeTableAttribute.Entry entry : characterRangeTableAttribute.entries) { + if ((entry.flags & CharacterRangeTableAttribute.CRT_BRANCH_FLAGS) != 0) { + LabelInfo.setPos(entry.startLabel, entry.charStart, + entry.charEnd); + } + } + } + } + + @Override public void visitLineNumber(final int line, final Label start) { currentLine = line; if (firstLine > line || lastLine == ISourceNode.UNKNOWN_LINE) { @@ -214,6 +229,25 @@ @Override public void visitJumpInsnWithProbe(final int opcode, final Label label, final int probeId, final IFrame frame) { + + if (probes != null && !probes[probeId]) { + final int labelCount = currentLabel.size(); + if (labelCount > 0) { + for (int i = labelCount; --i >= 0;) { + Label curLabel = currentLabel.get(i); + int charStart = LabelInfo.getCharStart(curLabel); + int charEnd = LabelInfo.getCharEnd(curLabel); + // TODO(Godin): not all branches are presented in + // CharacterRangeTableAttribute, for example "for-each" + // loops + System.out.println("branch not taken " + + CharacterRangeTableAttribute.decodePos(charStart) + + "-" + + CharacterRangeTableAttribute.decodePos(charEnd)); + } + } + } + visitInsn(); addProbe(probeId); }
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java index c6f1b76..5dffa09 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
@@ -41,10 +41,29 @@ private Instruction instruction = null; + private int charStart = 0; + private int charEnd = 0; + // instances are only created within this class private LabelInfo() { } + public static void setPos(final Label label, int charStart, int charEnd) { + LabelInfo info = create(label); + info.charStart = charStart; + info.charEnd = charEnd; + } + + public static int getCharStart(final Label label) { + LabelInfo info = create(label); + return info.charStart; + } + + public static int getCharEnd(final Label label) { + LabelInfo info = create(label); + return info.charEnd; + } + /** * Defines that the given label is a jump target. *
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java index 1400b63..622a668 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java
@@ -15,6 +15,7 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.commons.JSRInlinerAdapter; +import org.objectweb.asm.tree.LabelNode; /** * This method visitor fixes two potential issues with Java byte code: @@ -37,6 +38,16 @@ exceptions); } + // TODO(Godin): + // otherwise, if default implementation is used, labels will be changed + @Override + protected LabelNode getLabelNode(Label l) { + if (!(l.info instanceof LabelNode)) { + l.info = new LabelNode(l); + } + return (LabelNode) l.info; + } + @Override public void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end,