Use new filtering API for existing filter of methods in enums (#512)

diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
index 6da24ff..c71e52f 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
@@ -59,48 +59,4 @@
 		assertEquals(0, coverage.getMethods().size());
 	}
 
-	@Test
-	public void testMethodFilter_EnumValues() {
-		analyzer.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "Foo", null,
-				"java/lang/Enum", null);
-		final MethodProbesVisitor mv = analyzer.visitMethod(0, "values",
-				"()[LFoo;", null, null);
-		assertNull(mv);
-		assertTrue(coverage.getMethods().isEmpty());
-	}
-
-	@Test
-	public void testMethodFilter_EnumNonValues() {
-		analyzer.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "Foo", null,
-				"java/lang/Enum", null);
-		final MethodProbesVisitor mv = analyzer.visitMethod(0, "values", "()V",
-				null, null);
-		mv.visitCode();
-		mv.visitInsn(Opcodes.RETURN);
-		mv.visitEnd();
-		assertEquals(1, coverage.getMethods().size());
-	}
-
-	@Test
-	public void testMethodFilter_EnumValueOf() {
-		analyzer.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "Foo", null,
-				"java/lang/Enum", null);
-		final MethodProbesVisitor mv = analyzer.visitMethod(0, "valueOf",
-				"(Ljava/lang/String;)LFoo;", null, null);
-		assertNull(mv);
-		assertTrue(coverage.getMethods().isEmpty());
-	}
-
-	@Test
-	public void testMethodFilter_EnumNonValueOf() {
-		analyzer.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "Foo", null,
-				"java/lang/Enum", null);
-		final MethodProbesVisitor mv = analyzer.visitMethod(0, "valueOf", "()V",
-				null, null);
-		mv.visitCode();
-		mv.visitInsn(Opcodes.RETURN);
-		mv.visitEnd();
-		assertEquals(1, coverage.getMethods().size());
-	}
-
 }
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
index 6bcbd63..dbe0af6 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
@@ -580,8 +580,8 @@
 
 	private void runMethodAnalzer() {
 		LabelFlowAnalyzer.markLabels(method);
-		final MethodAnalyzer analyzer = new MethodAnalyzer("doit", "()V", null,
-				probes);
+		final MethodAnalyzer analyzer = new MethodAnalyzer("Foo",
+				"java/lang/Object", "doit", "()V", null, probes);
 		final MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
 				analyzer, this);
 		// note that CheckMethodAdapter verifies that this test does not violate
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java
new file mode 100644
index 0000000..149990f
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+public class EnumFilterTest implements IFilterOutput {
+
+	private final EnumFilter filter = new EnumFilter();
+
+	private AbstractInsnNode fromInclusive;
+	private AbstractInsnNode toInclusive;
+
+	@Test
+	public void testValues() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"values", "()[LFoo;", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter("Foo", "java/lang/Enum", m, this);
+
+		assertEquals(m.instructions.getFirst(), fromInclusive);
+		assertEquals(m.instructions.getLast(), toInclusive);
+	}
+
+	@Test
+	public void testNonValues() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"values", "()V", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter("Foo", "java/lang/Enum", m, this);
+
+		assertNull(fromInclusive);
+		assertNull(toInclusive);
+	}
+
+	@Test
+	public void testValueOf() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"valueOf", "(Ljava/lang/String;)LFoo;", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter("Foo", "java/lang/Enum", m, this);
+
+		assertEquals(m.instructions.getFirst(), fromInclusive);
+		assertEquals(m.instructions.getLast(), toInclusive);
+	}
+
+	@Test
+	public void testNonValueOf() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"valueOf", "()V", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter("Foo", "java/lang/Enum", m, this);
+
+		assertNull(fromInclusive);
+		assertNull(toInclusive);
+	}
+
+	@Test
+	public void testNonEnum() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"values", "()[LFoo;", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter("Foo", "java/lang/Object", m, this);
+
+		assertNull(fromInclusive);
+		assertNull(toInclusive);
+	}
+
+	public void ignore(final AbstractInsnNode fromInclusive,
+			final AbstractInsnNode toInclusive) {
+		assertNull(this.fromInclusive);
+		this.fromInclusive = fromInclusive;
+		this.toInclusive = toInclusive;
+	}
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java
index a1fdcae..58f93fb 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java
@@ -38,7 +38,7 @@
 		m.visitInsn(Opcodes.ICONST_0);
 		m.visitInsn(Opcodes.IRETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertNull(fromInclusive);
 		assertNull(toInclusive);
@@ -53,7 +53,7 @@
 		m.visitInsn(Opcodes.ICONST_0);
 		m.visitInsn(Opcodes.IRETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertNull(fromInclusive);
 		assertNull(toInclusive);
@@ -68,7 +68,7 @@
 		m.visitInsn(Opcodes.ICONST_0);
 		m.visitInsn(Opcodes.IRETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertEquals(m.instructions.getFirst(), fromInclusive);
 		assertEquals(m.instructions.getLast(), toInclusive);
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
index b315dda..b0f5d1b 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
@@ -63,7 +63,7 @@
 		m.visitLabel(exit);
 		m.visitInsn(Opcodes.RETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 		assertEquals(handler.info, fromInclusive);
 		assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive);
 	}
@@ -116,7 +116,7 @@
 		m.visitLabel(exit);
 		m.visitInsn(Opcodes.RETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 		assertNull(fromInclusive);
 	}
 
@@ -151,7 +151,7 @@
 		m.visitLabel(exit);
 		m.visitInsn(Opcodes.RETURN);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 		assertEquals(handler.info, fromInclusive);
 		assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive);
 	}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
index 75648dc..319caef 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
@@ -11,15 +11,15 @@
  *******************************************************************************/
 package org.jacoco.core.internal.analysis.filter;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
 import org.jacoco.core.internal.instr.InstrSupport;
 import org.junit.Test;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.tree.AbstractInsnNode;
 import org.objectweb.asm.tree.MethodNode;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
 public class SyntheticFilterTest implements IFilterOutput {
 
 	private final SyntheticFilter filter = new SyntheticFilter();
@@ -33,7 +33,7 @@
 				"name", "()V", null, null);
 		m.visitInsn(Opcodes.NOP);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertNull(fromInclusive);
 		assertNull(toInclusive);
@@ -45,7 +45,7 @@
 				Opcodes.ACC_SYNTHETIC, "name", "()V", null, null);
 		m.visitInsn(Opcodes.NOP);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertEquals(m.instructions.getFirst(), fromInclusive);
 		assertEquals(m.instructions.getLast(), toInclusive);
@@ -57,7 +57,7 @@
 				Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null);
 		m.visitInsn(Opcodes.NOP);
 
-		filter.filter(m, this);
+		filter.filter("Foo", "java/lang/Object", m, this);
 
 		assertNull(fromInclusive);
 		assertNull(toInclusive);
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java
index aaa5e98..69a2ed9 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java
@@ -29,7 +29,7 @@
 	/**
 	 * This method should not be excluded from analysis unlike implicitly
 	 * created {@link #valueOf(String)} method that refers to the line of enum
-	 * definition.
+	 * definition in case of javac and to the first line in case of ECJ.
 	 */
 	public void valueOf() {
 	} // $line-customValueOfMethod$
@@ -37,7 +37,7 @@
 	/**
 	 * This method should not be excluded from analysis unlike implicitly
 	 * created {@link #values()} method that refers to the line of enum
-	 * definition.
+	 * definition in case of javac and to the first line in case of ECJ.
 	 */
 	public void values(Object o) {
 	} // $line-customValuesMethod$
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
index 38037be..fa3517b 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
@@ -63,12 +63,8 @@
 
 		InstrSupport.assertNotInstrumented(name, coverage.getName());
 
-		if (isMethodFiltered(coverage.getName(), coverage.getSuperName(), name,
-				desc)) {
-			return null;
-		}
-
-		return new MethodAnalyzer(stringPool.get(name), stringPool.get(desc),
+		return new MethodAnalyzer(coverage.getName(), coverage.getSuperName(),
+				stringPool.get(name), stringPool.get(desc),
 				stringPool.get(signature), probes) {
 			@Override
 			public void visitEnd() {
@@ -82,27 +78,6 @@
 		};
 	}
 
-	/**
-	 * @return <code>true</code> if method should not be analyzed
-	 */
-	// TODO: Use filter hook in future
-	private boolean isMethodFiltered(final String className,
-			final String superClassName, final String name, final String desc) {
-		if ("java/lang/Enum".equals(superClassName)) {
-			// filter out methods that compiler creates for enums
-			if ("values".equals(name)
-					&& ("()[L" + className + ";").equals(desc)) {
-				return true;
-			}
-			if ("valueOf".equals(name)
-					&& ("(Ljava/lang/String;)L" + className + ";")
-							.equals(desc)) {
-				return true;
-			}
-		}
-		return false;
-	}
-
 	@Override
 	public FieldVisitor visitField(final int access, final String name,
 			final String desc, final String signature, final Object value) {
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 e5dde70..993fe88 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
@@ -19,6 +19,7 @@
 import org.jacoco.core.analysis.ICounter;
 import org.jacoco.core.analysis.IMethodCoverage;
 import org.jacoco.core.analysis.ISourceNode;
+import org.jacoco.core.internal.analysis.filter.EnumFilter;
 import org.jacoco.core.internal.analysis.filter.IFilter;
 import org.jacoco.core.internal.analysis.filter.IFilterOutput;
 import org.jacoco.core.internal.analysis.filter.LombokGeneratedFilter;
@@ -42,10 +43,14 @@
 public class MethodAnalyzer extends MethodProbesVisitor
 		implements IFilterOutput {
 
-	private static final IFilter[] FILTERS = new IFilter[] {
+	private static final IFilter[] FILTERS = new IFilter[] { new EnumFilter(),
 			new SyntheticFilter(), new SynchronizedFilter(),
 			new LombokGeneratedFilter() };
 
+	private final String className;
+
+	private final String superClassName;
+
 	private final boolean[] probes;
 
 	private final MethodCoverageImpl coverage;
@@ -74,6 +79,10 @@
 	/**
 	 * New Method analyzer for the given probe data.
 	 * 
+	 * @param className
+	 *            class name
+	 * @param superClassName
+	 *            superclass name
 	 * @param name
 	 *            method name
 	 * @param desc
@@ -85,9 +94,12 @@
 	 *            recorded probe date of the containing class or
 	 *            <code>null</code> if the class is not executed at all
 	 */
-	public MethodAnalyzer(final String name, final String desc,
-			final String signature, final boolean[] probes) {
+	public MethodAnalyzer(final String className, final String superClassName,
+			final String name, final String desc, final String signature,
+			final boolean[] probes) {
 		super();
+		this.className = className;
+		this.superClassName = superClassName;
 		this.probes = probes;
 		this.coverage = new MethodCoverageImpl(name, desc, signature);
 	}
@@ -110,7 +122,7 @@
 			final MethodVisitor methodVisitor) {
 		this.ignored.clear();
 		for (final IFilter filter : FILTERS) {
-			filter.filter(methodNode, this);
+			filter.filter(className, superClassName, methodNode, this);
 		}
 
 		for (final TryCatchBlockNode n : methodNode.tryCatchBlocks) {
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java
new file mode 100644
index 0000000..852008e
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.tree.MethodNode;
+
+/**
+ * Filters methods <code>values</code> and <code>valueOf</code> that compiler
+ * creates for enums.
+ */
+public final class EnumFilter implements IFilter {
+
+	public void filter(final String className, final String superClassName,
+			final MethodNode methodNode, final IFilterOutput output) {
+		if (isMethodFiltered(className, superClassName, methodNode.name,
+				methodNode.desc)) {
+			output.ignore(methodNode.instructions.getFirst(),
+					methodNode.instructions.getLast());
+		}
+	}
+
+	private boolean isMethodFiltered(final String className,
+			final String superClassName, final String methodName,
+			final String methodDesc) {
+		if ("java/lang/Enum".equals(superClassName)) {
+			if ("values".equals(methodName)
+					&& ("()[L" + className + ";").equals(methodDesc)) {
+				return true;
+			}
+			if ("valueOf".equals(methodName)
+					&& ("(Ljava/lang/String;)L" + className + ";")
+							.equals(methodDesc)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
index c1bab8e..39cf5c7 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
@@ -23,12 +23,17 @@
 	 * This method is called for every method. The filter implementation is
 	 * expected to inspect the provided method and report its result to the
 	 * given {@link IFilterOutput} instance.
-	 * 
+	 *
+	 * @param className
+	 *            class name
+	 * @param superClassName
+	 *            superclass name
 	 * @param methodNode
 	 *            method to inspect
 	 * @param output
 	 *            callback to report filtering results to
 	 */
-	void filter(MethodNode methodNode, IFilterOutput output);
+	void filter(String className, String superClassName, MethodNode methodNode,
+			IFilterOutput output);
 
 }
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java
index 9f23ecd..571e464 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java
@@ -21,8 +21,8 @@
  */
 public class LombokGeneratedFilter implements IFilter {
 
-	public void filter(final MethodNode methodNode,
-			final IFilterOutput output) {
+	public void filter(final String className, final String superClassName,
+			final MethodNode methodNode, final IFilterOutput output) {
 		if (hasLombokGeneratedAnnotation(methodNode)) {
 			output.ignore(methodNode.instructions.getFirst(),
 					methodNode.instructions.getLast());
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
index 65e763d..655226e 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
@@ -21,7 +21,8 @@
  */
 public final class SynchronizedFilter implements IFilter {
 
-	public void filter(MethodNode methodNode, IFilterOutput output) {
+	public void filter(final String className, final String superClassName,
+			final MethodNode methodNode, final IFilterOutput output) {
 		for (TryCatchBlockNode tryCatch : methodNode.tryCatchBlocks) {
 			if (tryCatch.type != null) {
 				continue;
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
index 540909d..454ec80 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
@@ -19,7 +19,8 @@
  */
 public final class SyntheticFilter implements IFilter {
 
-	public void filter(MethodNode methodNode, IFilterOutput output) {
+	public void filter(final String className, final String superClassName,
+			final MethodNode methodNode, final IFilterOutput output) {
 		if ((methodNode.access & Opcodes.ACC_SYNTHETIC) != 0
 				&& !methodNode.name.startsWith("lambda$")) {
 			output.ignore(methodNode.instructions.getFirst(),