aboutsummaryrefslogtreecommitdiff
path: root/org.jacoco.core/src/org/jacoco/core/internal/analysis
diff options
context:
space:
mode:
authorEvgeny Mandrikov <Godin@users.noreply.github.com>2017-09-24 07:28:44 +0200
committerMarc R. Hoffmann <hoffmann@mountainminds.com>2017-09-24 07:28:44 +0200
commit04f923c151b11c9b7f3a28f604ba65ec44dfa2ec (patch)
treedc9e84b05e737985af484b14fc7b29f5490de9d7 /org.jacoco.core/src/org/jacoco/core/internal/analysis
parent8cd3247107c1fcc0ef0add631f1f411da902a2bc (diff)
downloadjacoco-04f923c151b11c9b7f3a28f604ba65ec44dfa2ec.tar.gz
Add filter for bytecode that javac generates for String in switch (#596)
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal/analysis')
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java5
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java97
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java2
5 files changed, 104 insertions, 6 deletions
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 8e07e56f..328d079a 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
@@ -24,6 +24,7 @@ import org.jacoco.core.internal.analysis.filter.IFilter;
import org.jacoco.core.internal.analysis.filter.IFilterOutput;
import org.jacoco.core.internal.analysis.filter.LombokGeneratedFilter;
import org.jacoco.core.internal.analysis.filter.PrivateEmptyNoArgConstructorFilter;
+import org.jacoco.core.internal.analysis.filter.StringSwitchJavacFilter;
import org.jacoco.core.internal.analysis.filter.SynchronizedFilter;
import org.jacoco.core.internal.analysis.filter.SyntheticFilter;
import org.jacoco.core.internal.analysis.filter.TryWithResourcesEcjFilter;
@@ -49,7 +50,8 @@ public class MethodAnalyzer extends MethodProbesVisitor
private static final IFilter[] FILTERS = new IFilter[] { new EnumFilter(),
new SyntheticFilter(), new SynchronizedFilter(),
new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(),
- new PrivateEmptyNoArgConstructorFilter(), new LombokGeneratedFilter() };
+ new PrivateEmptyNoArgConstructorFilter(),
+ new StringSwitchJavacFilter(), new LombokGeneratedFilter() };
private final String className;
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
index 50a295de..c5edb2e4 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
@@ -25,14 +25,13 @@ abstract class AbstractMatcher {
AbstractInsnNode cursor;
- final void nextIsAddSuppressed() {
+ final void nextIsInvokeVirtual(final String owner, final String name) {
nextIs(Opcodes.INVOKEVIRTUAL);
if (cursor == null) {
return;
}
final MethodInsnNode m = (MethodInsnNode) cursor;
- if ("java/lang/Throwable".equals(m.owner)
- && "addSuppressed".equals(m.name)) {
+ if (owner.equals(m.owner) && name.equals(m.name)) {
return;
}
cursor = null;
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java
new file mode 100644
index 00000000..2824fce9
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TableSwitchInsnNode;
+
+/**
+ * Filters code that is generated by javac for a switch statement with a String.
+ */
+public final class StringSwitchJavacFilter implements IFilter {
+
+ public void filter(final String className, final String superClassName,
+ final MethodNode methodNode, final IFilterOutput output) {
+ AbstractInsnNode i = methodNode.instructions.getFirst();
+ while (i != null) {
+ filter(i, output);
+ i = i.getNext();
+ }
+ }
+
+ /**
+ * javac generates two switches. First one by {@link String#hashCode()}.
+ * Number of handlers in the second switch is equal to number of handlers in
+ * source code, so it is enough to completely filter-out first switch.
+ * Handler for default case of the first switch - is the second switch.
+ */
+ private void filter(final AbstractInsnNode start,
+ final IFilterOutput output) {
+ final LabelNode dflt;
+ if (start.getOpcode() == Opcodes.LOOKUPSWITCH) {
+ dflt = ((LookupSwitchInsnNode) start).dflt;
+ } else if (start.getOpcode() == Opcodes.TABLESWITCH) {
+ dflt = ((TableSwitchInsnNode) start).dflt;
+ } else {
+ return;
+ }
+ if (new Matcher().match(start, dflt)) {
+ output.ignore(start, dflt);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ boolean match(final AbstractInsnNode start,
+ final AbstractInsnNode secondSwitchLabel) {
+ cursor = start;
+ for (int i = 0; cursor != null && i < 4; i++) {
+ cursor = cursor.getPrevious();
+ }
+ if (cursor == null || cursor.getOpcode() != Opcodes.ICONST_M1) {
+ return false;
+ }
+ nextIsVar(Opcodes.ISTORE, "c");
+ nextIsVar(Opcodes.ALOAD, "s");
+ nextIsInvokeVirtual("java/lang/String", "hashCode");
+ next();
+ while (true) {
+ nextIsVar(Opcodes.ALOAD, "s");
+ nextIs(Opcodes.LDC);
+ nextIsInvokeVirtual("java/lang/String", "equals");
+ // jump to next comparison or second switch
+ nextIs(Opcodes.IFEQ);
+ // ICONST, BIPUSH or SIPUSH
+ next();
+ nextIsVar(Opcodes.ISTORE, "c");
+ if (cursor == null) {
+ return false;
+ }
+ if (cursor.getNext() == secondSwitchLabel) {
+ break;
+ }
+ nextIs(Opcodes.GOTO);
+ if (((JumpInsnNode) cursor).label != secondSwitchLabel) {
+ return false;
+ }
+ }
+ nextIsVar(Opcodes.ILOAD, "c");
+ nextIs(Opcodes.TABLESWITCH);
+ return cursor != null;
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
index 7d7d396c..aeceeae4 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
@@ -200,7 +200,7 @@ public final class TryWithResourcesEcjFilter implements IFilter {
// "primaryExc.addSuppressed(suppressedExc)"
nextIsVar(Opcodes.ALOAD, "primaryExc");
nextIsVar(Opcodes.ALOAD, suppressedExc);
- nextIsAddSuppressed();
+ nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed");
nextIsLabel(endLabel);
return cursor != null;
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
index 02ed47e5..49cacb3a 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
@@ -214,7 +214,7 @@ public final class TryWithResourcesJavacFilter implements IFilter {
// "primaryExc.addSuppressed(t)"
nextIsVar(Opcodes.ALOAD, "primaryExc");
nextIsVar(Opcodes.ALOAD, ctx + "t");
- nextIsAddSuppressed();
+ nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed");
nextIs(Opcodes.GOTO);
// "r.close()"
nextIsClose();