Skip to content

Commit a35f278

Browse files
dvdougsebastianbergmann
authored andcommitted
Mark empty lines as non-executable
1 parent 499eb11 commit a35f278

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/CodeCoverage.php

+2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ public function filter(): Filter
162162
*/
163163
public function getData(bool $raw = false): ProcessedCodeCoverageData
164164
{
165+
$this->data->finalize();
166+
165167
if (!$raw) {
166168
if ($this->processUncoveredFiles) {
167169
$this->processUncoveredFilesFromFilter();

src/ProcessedCodeCoverageData.php

+28
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,34 @@ public function merge(self $newData): void
188188
}
189189
}
190190

191+
public function finalize(): void
192+
{
193+
$this->ensureEmptyLinesAreMarkedNonExecutable();
194+
}
195+
196+
/**
197+
* At the end of a file, the PHP interpreter always sees an implicit return. Where this occurs in a file that has
198+
* e.g. a class definition, that line cannot be invoked from a test and results in confusing coverage. This engine
199+
* implementation detail therefore needs to be masked which is done here by simply ensuring that all empty lines
200+
* are considered non-executable for coverage purposes.
201+
*
202+
* @see https://github.com/sebastianbergmann/php-code-coverage/issues/799
203+
*/
204+
private function ensureEmptyLinesAreMarkedNonExecutable(): void
205+
{
206+
foreach ($this->lineCoverage as $filename => $coverage) {
207+
if (is_file($filename)) {
208+
$sourceLines = explode("\n", file_get_contents($filename));
209+
210+
foreach ($coverage as $line => $lineCoverage) {
211+
if (is_array($lineCoverage) && trim($sourceLines[$line - 1]) === '') {
212+
$this->lineCoverage[$filename][$line] = null;
213+
}
214+
}
215+
}
216+
}
217+
}
218+
191219
/**
192220
* Determine the priority for a line.
193221
*

0 commit comments

Comments
 (0)