GitHub #232: Get code coverage for Java 8 lambda expressions
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 a1484ef..45da7ee 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
@@ -11,6 +11,14 @@
  *******************************************************************************/
 package org.jacoco.core.internal.analysis;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+
+import org.jacoco.core.analysis.IMethodCoverage;
+import org.jacoco.core.internal.flow.MethodProbesVisitor;
 import org.jacoco.core.internal.instr.InstrSupport;
 import org.junit.Before;
 import org.junit.Test;
@@ -44,4 +52,48 @@
 				null, null);
 	}
 
+	@Test
+	public void testMethodFilter_Empty() {
+		final MethodProbesVisitor mv = analyzer.visitMethod(0, "foo", "()V",
+				null, null);
+		mv.visitEnd();
+		Collection<IMethodCoverage> methods = analyzer.getCoverage()
+				.getMethods();
+		assertEquals(0, methods.size());
+	}
+
+	@Test
+	public void testMethodFilter_NonSynthetic() {
+		final MethodProbesVisitor mv = analyzer.visitMethod(0, "foo", "()V",
+				null, null);
+		mv.visitCode();
+		mv.visitInsn(Opcodes.RETURN);
+		mv.visitEnd();
+		Collection<IMethodCoverage> methods = analyzer.getCoverage()
+				.getMethods();
+		assertEquals(1, methods.size());
+	}
+
+	@Test
+	public void testMethodFilter_Synthetic() {
+		final MethodProbesVisitor mv = analyzer.visitMethod(
+				Opcodes.ACC_SYNTHETIC, "foo", "()V", null, null);
+		assertNull(mv);
+		Collection<IMethodCoverage> methods = analyzer.getCoverage()
+				.getMethods();
+		assertTrue(methods.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();
+		Collection<IMethodCoverage> methods = analyzer.getCoverage()
+				.getMethods();
+		assertEquals(1, methods.size());
+	}
+
 }
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTarget.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTarget.java
new file mode 100644
index 0000000..4271db2
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTarget.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 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:
+ *    Marc R. Hoffmann - initial API and implementation
+ *    
+ *******************************************************************************/
+package org.jacoco.core.test.validation.java8;
+
+import static org.jacoco.core.test.validation.targets.Stubs.exec;
+import static org.jacoco.core.test.validation.targets.Stubs.noexec;
+import static org.jacoco.core.test.validation.targets.Stubs.nop;
+
+/**
+ * This test target contains different lambda expressions.
+ */
+public class LambdaExpressionsTarget implements Runnable {
+
+	@Override
+	public void run() {
+		
+		exec(() -> {
+			nop(); // $line-executedlambdabody$
+		});
+		
+		noexec(() -> {
+			nop(); // $line-notexecutedlambdabody$
+		});
+		
+	}
+
+	public static void main(String[] args) {
+		new LambdaExpressionsTarget().run();
+	}
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java
new file mode 100644
index 0000000..d552062
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 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:
+ *    Marc R. Hoffmann - initial API and implementation
+ *    
+ *******************************************************************************/
+package org.jacoco.core.test.validation.java8;
+
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.test.validation.ValidationTestBase;
+import org.junit.Test;
+
+/**
+ * Tests of basic Java control structures.
+ */
+public class LambdaExpressionsTest extends ValidationTestBase {
+
+	public LambdaExpressionsTest() {
+		super(LambdaExpressionsTarget.class);
+	}
+
+	@Override
+	protected void run(final Class<?> targetClass) throws Exception {
+		final Object instance = targetClass.newInstance();
+		((Runnable) instance).run();
+	}
+
+	@Test
+	public void testCoverageResult() {
+
+		// Coverage of lambda bodies
+		assertLine("executedlambdabody", ICounter.FULLY_COVERED);
+		assertLine("notexecutedlambdabody", ICounter.NOT_COVERED);
+
+	}
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Stubs.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Stubs.java
index fdea785..f5179c6 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Stubs.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Stubs.java
@@ -104,4 +104,17 @@
 		throw new StubException();
 	}
 
+	/**
+	 * Directly executes the given runnable.
+	 */
+	public static void exec(Runnable task) {
+		task.run();
+	}
+
+	/**
+	 * Never executes the given runnable.
+	 */
+	public static void noexec(Runnable task) {
+	}
+
 }
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 8508ab1..e43d21a 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
@@ -81,8 +81,7 @@
 
 		InstrSupport.assertNotInstrumented(name, coverage.getName());
 
-		// TODO: Use filter hook
-		if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+		if (isMethodFiltered(access, name)) {
 			return null;
 		}
 
@@ -100,6 +99,12 @@
 		};
 	}
 
+	// TODO: Use filter hook in future
+	private boolean isMethodFiltered(final int access, final String name) {
+		return (access & Opcodes.ACC_SYNTHETIC) != 0
+				&& !name.startsWith("lambda$");
+	}
+
 	@Override
 	public FieldVisitor visitField(final int access, final String name,
 			final String desc, final String signature, final Object value) {
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 79e2521..0c81770 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,13 +20,20 @@
 
 <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>Fixed Bugs</h3>
+<ul>
+  <li>Do not ignore synthetic lambda methods to get code coverage for Java 8
+      lambda expressions
+      (GitHub <a href="https://github.com/jacoco/jacoco/issues/232">#232</a>).</li>
+</ul>
+
 <h3>New Features</h3>
 <ul>
   <li>New configuration option for the JaCoCo agent
       <code>inclbootstrapclasses</code> to also instrument classes from the
-      bootstrap class loader.
+      bootstrap class loader
       (GitHub <a href="https://github.com/jacoco/jacoco/issues/49">#49</a>).</li>
-  <li>Agent uses unique file names to dump class files.
+  <li>Agent uses unique file names to dump class files
       (GitHub <a href="https://github.com/jacoco/jacoco/issues/225">#225</a>).</li>
 </ul>