Exclude enum methods "values" and "valueOf" from reports (#491)

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 d4e3999..9c8e6df 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
@@ -87,4 +87,48 @@
 		assertEquals(1, 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/test/validation/EnumImplicitMethodsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java
new file mode 100644
index 0000000..ddc1da1
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.validation;
+
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.test.validation.targets.EnumImplicitMethods;
+import org.junit.Test;
+
+/**
+ * Test of an implicit methods and static initializer in enums.
+ */
+public class EnumImplicitMethodsTest extends ValidationTestBase {
+
+    public EnumImplicitMethodsTest() {
+        super(EnumImplicitMethods.class);
+    }
+
+    @Test
+    public void testCoverageResult() {
+        assertLine("classdef", ICounter.FULLY_COVERED);
+        assertLine("customValueOfMethod", ICounter.NOT_COVERED);
+        assertLine("customValuesMethod", ICounter.NOT_COVERED);
+
+        assertLine("const", ICounter.PARTLY_COVERED);
+        assertLine("staticblock", ICounter.FULLY_COVERED);
+        assertLine("super", ICounter.FULLY_COVERED);
+        assertLine("constructor", ICounter.FULLY_COVERED);
+    }
+
+}
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
new file mode 100644
index 0000000..aaa5e98
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.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.test.validation.targets;
+
+public enum EnumImplicitMethods { // $line-classdef$
+
+	CONST(Stubs.f() ? new Object() : new Object()); // $line-const$
+
+	static {
+	} // $line-staticblock$
+
+	/**
+	 * Unlike in {@link Target07 regular classes}, even if enum has explicit
+	 * constructor, {@code clinit} method in any case has a reference to the
+	 * line of enum definition.
+	 */
+	EnumImplicitMethods(Object o) { // $line-super$
+	} // $line-constructor$
+
+	/**
+	 * This method should not be excluded from analysis unlike implicitly
+	 * created {@link #valueOf(String)} method that refers to the line of enum
+	 * definition.
+	 */
+	public void valueOf() {
+	} // $line-customValueOfMethod$
+
+	/**
+	 * This method should not be excluded from analysis unlike implicitly
+	 * created {@link #values()} method that refers to the line of enum
+	 * definition.
+	 */
+	public void values(Object o) {
+	} // $line-customValuesMethod$
+
+	public static void main(String[] args) {
+	}
+
+}
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 f32ef8d..06e1324 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
@@ -64,7 +64,8 @@
 
 		InstrSupport.assertNotInstrumented(name, coverage.getName());
 
-		if (isMethodFiltered(access, name)) {
+		if (isMethodFiltered(coverage.getName(), coverage.getSuperName(),
+				access, name, desc)) {
 			return null;
 		}
 
@@ -82,8 +83,25 @@
 		};
 	}
 
+	/**
+	 * @return <code>true</code> if method should not be analyzed
+	 */
 	// TODO: Use filter hook in future
-	private boolean isMethodFiltered(final int access, final String name) {
+	private boolean isMethodFiltered(final String className,
+			final String superClassName, final int access, 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 (access & Opcodes.ACC_SYNTHETIC) != 0
 				&& !name.startsWith("lambda$");
 	}
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 75ddce0..34b36b2 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,13 @@
 
 <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2>
 
+<h3>New Features</h3>
+<ul>
+  <li>Exclude from a report enum methods <code>valueOf</code> and <code>values</code>
+      that are created by compiler
+      (GitHub <a href="https://github.com/jacoco/jacoco/issues/491">#491</a>).</li>
+</ul>
+
 <h2>Release 0.7.9 (2017/02/05)</h2>
 
 <h3>Fixed Bugs</h3>