SF #3161106: Allow any number of probes in static interface initializers
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
index 321026a..b2c6c00 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java
@@ -53,7 +53,7 @@
}
@Test
- public void testVisitMethod() {
+ public void testVisitClassMethods() {
final MockVisitor mv = new MockVisitor() {
@Override
public IMethodProbesVisitor visitMethod(int access, String name,
@@ -82,14 +82,56 @@
}
};
final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
+ adapter.visit(Opcodes.V1_5, 0, "Foo", null, "java/lang/Object", null);
writeMethod(adapter);
writeMethod(adapter);
writeMethod(adapter);
+
+ assertEquals(0, mv.count);
adapter.visitEnd();
assertEquals(3, mv.count);
}
@Test
+ public void testVisitInterfaceMethod() {
+ final MockVisitor mv = new MockVisitor() {
+ @Override
+ public IMethodProbesVisitor visitMethod(int access, String name,
+ String desc, String signature, String[] exceptions) {
+ class MockMethodVisitor extends EmptyVisitor implements
+ IMethodProbesVisitor {
+ public void visitProbe(int probeId) {
+ }
+
+ public void visitJumpInsnWithProbe(int opcode, Label label,
+ int probeId) {
+ }
+
+ public void visitInsnWithProbe(int opcode, int probeId) {
+ }
+
+ public void visitTableSwitchInsnWithProbes(int min,
+ int max, Label dflt, Label[] labels) {
+ }
+
+ public void visitLookupSwitchInsnWithProbes(Label dflt,
+ int[] keys, Label[] labels) {
+ }
+ }
+ return new MockMethodVisitor();
+ }
+ };
+ final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
+ adapter.visit(Opcodes.V1_5, Opcodes.ACC_INTERFACE, "Foo", null,
+ "java/lang/Object", null);
+ writeMethod(adapter);
+
+ assertEquals(1, mv.count);
+ adapter.visitEnd();
+ assertEquals(1, mv.count);
+ }
+
+ @Test
public void testVisitMethodNullMethodVisitor() {
final MockVisitor mv = new MockVisitor();
final ClassProbesAdapter adapter = new ClassProbesAdapter(mv);
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
index f8ac8b1..eda8f6d 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java
@@ -40,13 +40,14 @@
actual = new MethodRecorder();
expected = new MethodRecorder();
probeArrayStrategy = new IProbeArrayStrategy() {
+
public int pushInstance(MethodVisitor mv) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "Target",
"$jacocoInit", "()[Z");
return 1;
}
- public void addMembers(ClassVisitor delegate, int probeCount) {
+ public void addMembers(ClassVisitor delegate) {
}
};
instrumenter = new MethodInstrumenter(actual, 0, "()V",
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
index 60e4cb3..fe09dfb 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
@@ -15,6 +15,7 @@
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.commons.JSRInlinerAdapter;
@@ -50,10 +51,20 @@
EMPTY_BLOCK_METHOD_VISITOR = new Impl();
}
+ private static class ProbeCounter implements IProbeIdGenerator {
+ int count = 0;
+
+ public int nextId() {
+ return count++;
+ }
+ }
+
private final IClassProbesVisitor cv;
private int counter = 0;
+ private boolean interfaceType;
+
/**
* Creates a new adapter that delegates to the given visitor.
*
@@ -66,6 +77,14 @@
}
@Override
+ public void visit(final int version, final int access, final String name,
+ final String signature, final String superName,
+ final String[] interfaces) {
+ interfaceType = (access & Opcodes.ACC_INTERFACE) != 0;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
public final MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
final IMethodProbesVisitor methodProbes;
@@ -84,6 +103,12 @@
public void visitEnd() {
super.visitEnd();
this.accept(new LabelFlowAnalyzer());
+ if (interfaceType) {
+ final ProbeCounter counter = new ProbeCounter();
+ this.accept(new MethodProbesAdapter(
+ EMPTY_BLOCK_METHOD_VISITOR, counter));
+ cv.visitTotalProbeCount(counter.count);
+ }
this.accept(new MethodProbesAdapter(methodProbes,
ClassProbesAdapter.this));
}
@@ -92,7 +117,9 @@
@Override
public void visitEnd() {
- cv.visitTotalProbeCount(counter);
+ if (!interfaceType) {
+ cv.visitTotalProbeCount(counter);
+ }
super.visitEnd();
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java
index 67fcb7c..afb4a55 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java
@@ -23,8 +23,10 @@
String desc, String signature, String[] exceptions);
/**
- * Reports the total number of encountered probes. This method is called
- * just before {@link ClassVisitor#visitEnd()}.
+ * Reports the total number of encountered probes. For classes this method
+ * is called just before {@link ClassVisitor#visitEnd()}. For interfaces
+ * this method is called before the first method (the static initializer) is
+ * emitted.
*
* @param count
* total number of probes
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
index 1c5a126..15e7e01 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
@@ -39,6 +39,8 @@
private String className;
+ private int probeCount;
+
/**
* Emits a instrumented version of this class to the given class visitor.
*
@@ -95,7 +97,13 @@
}
public void visitTotalProbeCount(final int count) {
- probeArrayStrategy.addMembers(cv, count);
+ probeCount = count;
+ }
+
+ @Override
+ public void visitEnd() {
+ probeArrayStrategy.addMembers(cv);
+ super.visitEnd();
}
/**
@@ -129,7 +137,7 @@
return 1;
}
- public void addMembers(final ClassVisitor delegate, final int probeCount) {
+ public void addMembers(final ClassVisitor delegate) {
createDataField();
createInitMethod(probeCount);
}
@@ -207,17 +215,11 @@
private class InterfaceTypeStrategy implements IProbeArrayStrategy {
public int pushInstance(final MethodVisitor mv) {
- // TODO As we don't know the actual probe count at this point in
- // time use a hard coded value of 64. This is typically be way too
- // big and will break static initializers in interfaces with more
- // than 64 blocks. So this has to be replaced with the actual probe
- // count.
- final int size = accessorGenerator.generateDataAccessor(id,
- className, 64, mv);
- return size;
+ return accessorGenerator.generateDataAccessor(id, className,
+ probeCount, mv);
}
- public void addMembers(final ClassVisitor delegate, final int probeCount) {
+ public void addMembers(final ClassVisitor delegate) {
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
index f24fafb..1a9110a 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
@@ -35,9 +35,7 @@
*
* @param delegate
* visitor to create fields and classes
- * @param probeCount
- * total number of probes inserted into this class
*/
- void addMembers(ClassVisitor delegate, int probeCount);
+ void addMembers(ClassVisitor delegate);
}
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index f7bd4fe..c9ad3b7 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -33,6 +33,7 @@
<li>Try to avoid interference with Hibernate (SF #3134190).</li>
<li>Provide proper error message in case of duplicate class names in the same
group (SF #3110219).</li>
+ <li>Allow any number of probes in static interface initializers (SF #3161106).</li>
</ul>
<h3>API Changes</h3>