From 252cc6d7922eec7e27e2049136a25858f17c0a17 Mon Sep 17 00:00:00 2001
From: Doug Wright <github@dougweb.org>
Date: Fri, 28 Aug 2020 16:55:34 +0100
Subject: [PATCH 1/2] Correct line numbers in fixture data after c5fc69

---
 tests/TestCase.php                          | 62 ++++++++++-----------
 tests/_files/NamespacedBankAccount-text.txt |  2 +-
 2 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/tests/TestCase.php b/tests/TestCase.php
index 7e025527d..52e8f042b 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -1122,48 +1122,48 @@ protected function getXdebugDataForNamespacedBankAccount()
         return [
             RawCodeCoverageData::fromXdebugWithoutPathCoverage([
                 TEST_FILES_PATH . 'NamespacedBankAccount.php' => [
-                    14 => 1,
-                    15 => -2,
+                    13 => 1,
+                    14 => -2,
+                    18 => -1,
                     19 => -1,
                     20 => -1,
                     21 => -1,
-                    22 => -1,
-                    24 => -1,
-                    28 => -1,
-                    30 => -1,
-                    31 => -2,
-                    35 => -1,
-                    37 => -1,
-                    38 => -2,
+                    23 => -1,
+                    27 => -1,
+                    29 => -1,
+                    30 => -2,
+                    34 => -1,
+                    36 => -1,
+                    37 => -2,
                 ],
             ]),
             RawCodeCoverageData::fromXdebugWithoutPathCoverage([
                 TEST_FILES_PATH . 'NamespacedBankAccount.php' => [
-                    14 => 1,
-                    19 => 1,
-                    22 => 1,
-                    35 => 1,
+                    13 => 1,
+                    18 => 1,
+                    21 => 1,
+                    34 => 1,
                 ],
             ]),
             RawCodeCoverageData::fromXdebugWithoutPathCoverage([
                 TEST_FILES_PATH . 'NamespacedBankAccount.php' => [
-                    14 => 1,
-                    19 => 1,
-                    22 => 1,
-                    28 => 1,
+                    13 => 1,
+                    18 => 1,
+                    21 => 1,
+                    27 => 1,
                 ],
             ]),
             RawCodeCoverageData::fromXdebugWithoutPathCoverage([
                 TEST_FILES_PATH . 'NamespacedBankAccount.php' => [
-                    14 => 1,
+                    13 => 1,
+                    18 => 1,
                     19 => 1,
                     20 => 1,
-                    21 => 1,
-                    24 => 1,
-                    28 => 1,
-                    30 => 1,
-                    35 => 1,
-                    37 => 1,
+                    23 => 1,
+                    27 => 1,
+                    29 => 1,
+                    34 => 1,
+                    36 => 1,
                 ],
             ]),
         ];
@@ -1190,7 +1190,7 @@ protected function getLineCoverageForNamespacedBankAccount(): CodeCoverage
 
         $coverage->stop(
             true,
-            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(12, 15)]
+            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(11, 14)]
         );
 
         $coverage->start(
@@ -1199,7 +1199,7 @@ protected function getLineCoverageForNamespacedBankAccount(): CodeCoverage
 
         $coverage->stop(
             true,
-            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(33, 38)]
+            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(32, 37)]
         );
 
         $coverage->start(
@@ -1208,7 +1208,7 @@ protected function getLineCoverageForNamespacedBankAccount(): CodeCoverage
 
         $coverage->stop(
             true,
-            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(26, 31)]
+            [TEST_FILES_PATH . 'NamespacedBankAccount.php' => range(25, 30)]
         );
 
         $coverage->start(
@@ -1219,9 +1219,9 @@ protected function getLineCoverageForNamespacedBankAccount(): CodeCoverage
             true,
             [
                 TEST_FILES_PATH . 'NamespacedBankAccount.php' => array_merge(
-                    range(12, 15),
-                    range(26, 31),
-                    range(33, 38)
+                    range(11, 14),
+                    range(25, 30),
+                    range(32, 37)
                 ),
             ]
         );
diff --git a/tests/_files/NamespacedBankAccount-text.txt b/tests/_files/NamespacedBankAccount-text.txt
index 316d58170..612512661 100644
--- a/tests/_files/NamespacedBankAccount-text.txt
+++ b/tests/_files/NamespacedBankAccount-text.txt
@@ -11,4 +11,4 @@ Code Coverage Report:
 SomeNamespace\BankAccount
   Methods:  ( 0/ 0)   Lines:  (  0/  0)
 SomeNamespace\BankAccountTrait
-  Methods:  75.00% ( 3/ 4)   Lines:  55.56% (  5/  9)
+  Methods:  75.00% ( 3/ 4)   Lines:  50.00% (  5/ 10)

From 1000da7e86cc0dba421d7788d93252936219e806 Mon Sep 17 00:00:00 2001
From: Doug Wright <github@dougweb.org>
Date: Fri, 28 Aug 2020 16:57:22 +0100
Subject: [PATCH 2/2] Mark empty lines as non-executable

---
 src/CodeCoverage.php              |  2 ++
 src/ProcessedCodeCoverageData.php | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/src/CodeCoverage.php b/src/CodeCoverage.php
index e14283bea..d301462bb 100644
--- a/src/CodeCoverage.php
+++ b/src/CodeCoverage.php
@@ -162,6 +162,8 @@ public function filter(): Filter
      */
     public function getData(bool $raw = false): ProcessedCodeCoverageData
     {
+        $this->data->finalize();
+
         if (!$raw) {
             if ($this->processUncoveredFiles) {
                 $this->processUncoveredFilesFromFilter();
diff --git a/src/ProcessedCodeCoverageData.php b/src/ProcessedCodeCoverageData.php
index 1ed29ad52..8a102f211 100644
--- a/src/ProcessedCodeCoverageData.php
+++ b/src/ProcessedCodeCoverageData.php
@@ -188,6 +188,34 @@ public function merge(self $newData): void
         }
     }
 
+    public function finalize(): void
+    {
+        $this->ensureEmptyLinesAreMarkedNonExecutable();
+    }
+
+    /**
+     * At the end of a file, the PHP interpreter always sees an implicit return. Where this occurs in a file that has
+     * e.g. a class definition, that line cannot be invoked from a test and results in confusing coverage. This engine
+     * implementation detail therefore needs to be masked which is done here by simply ensuring that all empty lines
+     * are considered non-executable for coverage purposes.
+     *
+     * @see https://github.com/sebastianbergmann/php-code-coverage/issues/799
+     */
+    private function ensureEmptyLinesAreMarkedNonExecutable(): void
+    {
+        foreach ($this->lineCoverage as $filename => $coverage) {
+            if (is_file($filename)) {
+                $sourceLines = explode("\n", file_get_contents($filename));
+
+                foreach ($coverage as $line => $lineCoverage) {
+                    if (is_array($lineCoverage) && trim($sourceLines[$line - 1]) === '') {
+                        $this->lineCoverage[$filename][$line] = null;
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Determine the priority for a line.
      *