Use new filtering API for existing filter of synthetic methods (#511)

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 9c8e6df..6da24ff 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
@@ -60,34 +60,6 @@
 	}
 
 	@Test
-	public void testMethodFilter_NonSynthetic() {
-		final MethodProbesVisitor mv = analyzer.visitMethod(0, "foo", "()V",
-				null, null);
-		mv.visitCode();
-		mv.visitInsn(Opcodes.RETURN);
-		mv.visitEnd();
-		assertEquals(1, coverage.getMethods().size());
-	}
-
-	@Test
-	public void testMethodFilter_Synthetic() {
-		final MethodProbesVisitor mv = analyzer.visitMethod(
-				Opcodes.ACC_SYNTHETIC, "foo", "()V", null, null);
-		assertNull(mv);
-		assertTrue(coverage.getMethods().isEmpty());
-	}
-
-	@Test
-	public void testMethodFilter_Lambda() {
-		final MethodProbesVisitor mv = analyzer.visitMethod(
-				Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null);
-		mv.visitCode();
-		mv.visitInsn(Opcodes.RETURN);
-		mv.visitEnd();
-		assertEquals(1, coverage.getMethods().size());
-	}
-
-	@Test
 	public void testMethodFilter_EnumValues() {
 		analyzer.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "Foo", null,
 				"java/lang/Enum", null);
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
new file mode 100644
index 0000000..75648dc
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.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();
+
+	private AbstractInsnNode fromInclusive;
+	private AbstractInsnNode toInclusive;
+
+	@Test
+	public void testNonSynthetic() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+				"name", "()V", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter(m, this);
+
+		assertNull(fromInclusive);
+		assertNull(toInclusive);
+	}
+
+	@Test
+	public void testSynthetic() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+				Opcodes.ACC_SYNTHETIC, "name", "()V", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter(m, this);
+
+		assertEquals(m.instructions.getFirst(), fromInclusive);
+		assertEquals(m.instructions.getLast(), toInclusive);
+	}
+
+	@Test
+	public void testLambda() {
+		final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+				Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null);
+		m.visitInsn(Opcodes.NOP);
+
+		filter.filter(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/test/filter/SyntheticTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java
new file mode 100644
index 0000000..a0b54e0
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.test.filter;
+
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.test.filter.targets.Synthetic;
+import org.jacoco.core.test.validation.ValidationTestBase;
+import org.junit.Test;
+
+/**
+ * Test of filtering of synthetic methods.
+ */
+public class SyntheticTest extends ValidationTestBase {
+
+	public SyntheticTest() {
+		super(Synthetic.class);
+	}
+
+	@Test
+	public void testCoverageResult() {
+		assertMethodCount(6);
+
+		assertLine("classdef", ICounter.EMPTY);
+		assertLine("field", ICounter.EMPTY);
+
+		assertLine("inner.classdef", ICounter.EMPTY);
+	}
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java
new file mode 100644
index 0000000..4a9adfd
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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.test.filter.targets;
+
+/**
+ * This test target is synthetic methods.
+ */
+public class Synthetic { // $line-classdef$
+
+	private static int counter; // $line-field$
+
+	private Synthetic() {
+	}
+
+	private static class Inner extends Synthetic { // $line-inner.classdef$
+		Inner() {
+		}
+
+		/**
+		 * Access to private field of outer class causes creation of synthetic
+		 * methods in it. In case of javac those methods refer to the line of
+		 * outer class definition, in case of ECJ - to the line of field.
+		 */
+		private static void inc() {
+			counter = counter + 2;
+		}
+
+		/**
+		 * Difference of return type with overridden method causes creation of
+		 * synthetic bridge method in this class. In case of javac this method
+		 * refers to the line of inner class definition, in case of EJC - to the
+		 * first line of file.
+		 */
+		@Override
+		public String get() {
+			return null;
+		}
+	}
+
+	public Object get() {
+		return null;
+	}
+
+	public static void main(String[] args) {
+		Inner.inc();
+	}
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java
index ddc1da1..643b599 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java
@@ -26,6 +26,8 @@
 
     @Test
     public void testCoverageResult() {
+        assertMethodCount(5);
+
         assertLine("classdef", ICounter.FULLY_COVERED);
         assertLine("customValueOfMethod", ICounter.NOT_COVERED);
         assertLine("customValuesMethod", ICounter.NOT_COVERED);
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java
index 46a19a5..c8693f9 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java
@@ -109,6 +109,11 @@
 		analyzer.analyzeClass(bytes, data.getName());
 	}
 
+	protected void assertMethodCount(final int expectedTotal) {
+		assertEquals(expectedTotal,
+				sourceCoverage.getMethodCounter().getTotalCount());
+	}
+
 	protected void assertLine(final String tag, final int status) {
 		final int nr = source.getLineNumber(tag);
 		final ILine line = sourceCoverage.getLine(nr);
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 06e1324..38037be 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
@@ -16,7 +16,6 @@
 import org.jacoco.core.internal.flow.MethodProbesVisitor;
 import org.jacoco.core.internal.instr.InstrSupport;
 import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Opcodes;
 
 /**
  * Analyzes the structure of a class.
@@ -64,8 +63,8 @@
 
 		InstrSupport.assertNotInstrumented(name, coverage.getName());
 
-		if (isMethodFiltered(coverage.getName(), coverage.getSuperName(),
-				access, name, desc)) {
+		if (isMethodFiltered(coverage.getName(), coverage.getSuperName(), name,
+				desc)) {
 			return null;
 		}
 
@@ -88,8 +87,7 @@
 	 */
 	// TODO: Use filter hook in future
 	private boolean isMethodFiltered(final String className,
-			final String superClassName, final int access, final String name,
-			final String desc) {
+			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)
@@ -102,8 +100,7 @@
 				return true;
 			}
 		}
-		return (access & Opcodes.ACC_SYNTHETIC) != 0
-				&& !name.startsWith("lambda$");
+		return false;
 	}
 
 	@Override
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 6736aca..a912e33 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
@@ -22,6 +22,7 @@
 import org.jacoco.core.internal.analysis.filter.IFilter;
 import org.jacoco.core.internal.analysis.filter.IFilterOutput;
 import org.jacoco.core.internal.analysis.filter.SynchronizedFilter;
+import org.jacoco.core.internal.analysis.filter.SyntheticFilter;
 import org.jacoco.core.internal.flow.IFrame;
 import org.jacoco.core.internal.flow.Instruction;
 import org.jacoco.core.internal.flow.LabelInfo;
@@ -41,7 +42,7 @@
 		implements IFilterOutput {
 
 	private static final IFilter[] FILTERS = new IFilter[] {
-			new SynchronizedFilter() };
+			new SyntheticFilter(), new SynchronizedFilter() };
 
 	private final boolean[] probes;
 
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
new file mode 100644
index 0000000..540909d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.MethodNode;
+
+/**
+ * Filters synthetic methods unless they represent bodies of lambda expressions.
+ */
+public final class SyntheticFilter implements IFilter {
+
+	public void filter(MethodNode methodNode, IFilterOutput output) {
+		if ((methodNode.access & Opcodes.ACC_SYNTHETIC) != 0
+				&& !methodNode.name.startsWith("lambda$")) {
+			output.ignore(methodNode.instructions.getFirst(),
+					methodNode.instructions.getLast());
+		}
+	}
+
+}