Skip to content

Do not depend on phpunit/php-token-stream #777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* [#754](https://github.com/sebastianbergmann/php-code-coverage/pull/754): Implement collection of raw branch and path coverage
* [#755](https://github.com/sebastianbergmann/php-code-coverage/pull/755): Implement processing of raw branch and path coverage
* [#756](https://github.com/sebastianbergmann/php-code-coverage/pull/756): Improve handling of uncovered files
* `SebastianBergmann\CodeCoverage\CodeCoverage::getCacheTokens()` has been renamed to `SebastianBergmann\CodeCoverage\CodeCoverage::cachesTokens()`
* `SebastianBergmann\CodeCoverage\Filter::addDirectoryToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeDirectory()`
* `SebastianBergmann\CodeCoverage\Filter::addFilesToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFiles()`
* `SebastianBergmann\CodeCoverage\Filter::addFileToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFile()`
Expand All @@ -32,7 +31,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt

### Removed

* `SebastianBergmann\CodeCoverage\CodeCoverage::setCacheTokens()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableTokenCaching()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableTokenCaching()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCacheTokens()` and `SebastianBergmann\CodeCoverage\CodeCoverage::getCacheTokens()` have been removed
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForUnintentionallyCoveredCode()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableCheckForUnintentionallyCoveredCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableCheckForUnintentionallyCoveredCode()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setSubclassesExcludedFromUnintentionallyCoveredCodeCheck()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setAddUncoveredFilesFromWhitelist()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::includeUncoveredFiles()` or `SebastianBergmann\CodeCoverage\CodeCoverage::excludeUncoveredFiles()` instead
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"php": "^7.3 || ^8.0",
"ext-dom": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.6",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
"phpunit/php-token-stream": "^4.0.3",
Expand Down
170 changes: 24 additions & 146 deletions src/CodeCoverage.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,18 @@
use function array_values;
use function count;
use function explode;
use function file;
use function file_exists;
use function get_class;
use function is_array;
use function sort;
use function strpos;
use function trim;
use OutOfBoundsException;
use PHP_Token_CLASS;
use PHP_Token_COMMENT;
use PHP_Token_DOC_COMMENT;
use PHP_Token_FUNCTION;
use PHP_Token_INTERFACE;
use PHP_Token_Stream;
use PHP_Token_Stream_CachingFactory;
use PHP_Token_TRAIT;
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Test;
use ReflectionClass;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\Node\Builder;
use SebastianBergmann\CodeCoverage\Node\Directory;
use SebastianBergmann\CodeCoverage\StaticAnalysis\IgnoredLinesFinder;
use SebastianBergmann\CodeUnitReverseLookup\Wizard;

/**
Expand All @@ -65,11 +54,6 @@ final class CodeCoverage
*/
private $wizard;

/**
* @var bool
*/
private $cacheTokens = false;

/**
* @var bool
*/
Expand Down Expand Up @@ -103,14 +87,14 @@ final class CodeCoverage
private $data;

/**
* @var array
* @var IgnoredLinesFinder
*/
private $ignoredLines = [];
private $ignoredLinesFinder;

/**
* @var bool
*/
private $disableIgnoredLines = false;
private $useAnnotationsForIgnoringCode = true;

/**
* Test data.
Expand All @@ -133,10 +117,11 @@ final class CodeCoverage

public function __construct(Driver $driver, Filter $filter)
{
$this->driver = $driver;
$this->filter = $filter;
$this->data = new ProcessedCodeCoverageData;
$this->wizard = new Wizard;
$this->driver = $driver;
$this->filter = $filter;
$this->data = new ProcessedCodeCoverageData;
$this->ignoredLinesFinder = new IgnoredLinesFinder;
$this->wizard = new Wizard;
}

/**
Expand Down Expand Up @@ -264,7 +249,10 @@ public function append(RawCodeCoverageData $rawData, $id = null, bool $append =
}

$this->applyFilter($rawData);
$this->applyIgnoredLinesFilter($rawData);

if ($this->useAnnotationsForIgnoringCode) {
$this->applyIgnoredLinesFilter($rawData);
}

$this->data->initializeUnseenData($rawData);

Expand Down Expand Up @@ -326,21 +314,6 @@ public function merge(self $that): void
$this->tests = array_merge($this->tests, $that->getTests());
}

public function enableTokenCaching(): void
{
$this->cacheTokens = true;
}

public function disableTokenCaching(): void
{
$this->cacheTokens = false;
}

public function cachesTokens(): bool
{
return $this->cacheTokens;
}

public function enableCheckForUnintentionallyCoveredCode(): void
{
$this->checkForUnintentionallyCoveredCode = true;
Expand Down Expand Up @@ -373,12 +346,12 @@ public function doNotProcessUncoveredFiles(): void

public function enableAnnotationsForIgnoringCode(): void
{
$this->disableIgnoredLines = false;
$this->useAnnotationsForIgnoringCode = true;
}

public function disableAnnotationsForIgnoringCode(): void
{
$this->disableIgnoredLines = true;
$this->useAnnotationsForIgnoringCode = false;
}

public function ignoreDeprecatedCode(): void
Expand Down Expand Up @@ -479,7 +452,14 @@ private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void
continue;
}

$data->removeCoverageDataForLines($filename, $this->getLinesToBeIgnored($filename));
$data->removeCoverageDataForLines(
$filename,
$this->ignoredLinesFinder->findIgnoredLinesInFile(
$filename,
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode
)
);
}
}

Expand All @@ -495,111 +475,9 @@ private function addUncoveredFilesFromFilter(): void

foreach ($uncoveredFiles as $uncoveredFile) {
if (file_exists($uncoveredFile)) {
if ($this->cacheTokens) {
$tokens = PHP_Token_Stream_CachingFactory::get($uncoveredFile);
} else {
$tokens = new PHP_Token_Stream($uncoveredFile);
}

$this->append(RawCodeCoverageData::fromUncoveredFile($uncoveredFile, $tokens), self::UNCOVERED_FILES);
}
}
}

private function getLinesToBeIgnored(string $fileName): array
{
if (isset($this->ignoredLines[$fileName])) {
return $this->ignoredLines[$fileName];
}

try {
return $this->getLinesToBeIgnoredInner($fileName);
} catch (OutOfBoundsException $e) {
// This can happen with PHP_Token_Stream if the file is syntactically invalid,
// and probably affects a file that wasn't executed.
return [];
}
}

private function getLinesToBeIgnoredInner(string $fileName): array
{
$this->ignoredLines[$fileName] = [];

if ($this->cacheTokens) {
$tokens = PHP_Token_Stream_CachingFactory::get($fileName);
} else {
$tokens = new PHP_Token_Stream($fileName);
}

if ($this->disableIgnoredLines) {
$this->ignoredLines[$fileName] = array_unique($this->ignoredLines[$fileName]);
sort($this->ignoredLines[$fileName]);

return $this->ignoredLines[$fileName];
}

$ignore = false;
$stop = false;

foreach ($tokens->tokens() as $token) {
switch (get_class($token)) {
case PHP_Token_COMMENT::class:
case PHP_Token_DOC_COMMENT::class:
$_token = trim((string) $token);

if ($_token === '// @codeCoverageIgnore' ||
$_token === '//@codeCoverageIgnore') {
$ignore = true;
$stop = true;
} elseif ($_token === '// @codeCoverageIgnoreStart' ||
$_token === '//@codeCoverageIgnoreStart') {
$ignore = true;
} elseif ($_token === '// @codeCoverageIgnoreEnd' ||
$_token === '//@codeCoverageIgnoreEnd') {
$stop = true;
}

break;

case PHP_Token_INTERFACE::class:
case PHP_Token_TRAIT::class:
case PHP_Token_CLASS::class:
$this->ignoredLines[$fileName][] = $token->getLine(); //work around https://bugs.xdebug.org/view.php?id=1798
// Intentional fallthrough
case PHP_Token_FUNCTION::class:
/* @var \PHP_Token_Interface $token */

$docblock = (string) $token->getDocblock();

if (strpos($docblock, '@codeCoverageIgnore') || ($this->ignoreDeprecatedCode && strpos($docblock, '@deprecated'))) {
$endLine = $token->getEndLine();

for ($i = $token->getLine(); $i <= $endLine; $i++) {
$this->ignoredLines[$fileName][] = $i;
}
}

break;
}

if ($ignore) {
$this->ignoredLines[$fileName][] = $token->getLine();

if ($stop) {
$ignore = false;
$stop = false;
}
$this->append(RawCodeCoverageData::fromUncoveredFile($uncoveredFile), self::UNCOVERED_FILES);
}
}

$this->ignoredLines[$fileName] = array_unique(
$this->ignoredLines[$fileName]
);

$this->ignoredLines[$fileName] = array_unique($this->ignoredLines[$fileName]);
sort($this->ignoredLines[$fileName]);

return $this->ignoredLines[$fileName];
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Driver/Xdebug3Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use const XDEBUG_FILTER_CODE_COVERAGE;
use const XDEBUG_PATH_INCLUDE;
use function extension_loaded;
use function in_array;
use function ini_get;
use function phpversion;
use function sprintf;
Expand Down Expand Up @@ -51,7 +52,7 @@ public function __construct(Filter $filter)
);
}

if (!ini_get('xdebug.mode') || ini_get('xdebug.mode') !== 'coverage') {
if (!ini_get('xdebug.mode') || !in_array('coverage', explode(',', ini_get('xdebug.mode')))) {
throw new Xdebug3NotEnabledException;
}

Expand Down
9 changes: 4 additions & 5 deletions src/Node/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,13 @@ public function build(CodeCoverage $coverage): Directory
$this->addItems(
$root,
$this->buildDirectoryStructure($data),
$coverage->getTests(),
$coverage->cachesTokens()
$coverage->getTests()
);

return $root;
}

private function addItems(Directory $root, array $items, array $tests, bool $cacheTokens): void
private function addItems(Directory $root, array $items, array $tests): void
{
foreach ($items as $key => $value) {
$key = (string) $key;
Expand All @@ -56,11 +55,11 @@ private function addItems(Directory $root, array $items, array $tests, bool $cac
$key = substr($key, 0, -2);

if (file_exists($root->pathAsString() . DIRECTORY_SEPARATOR . $key)) {
$root->addFile($key, $value['lineCoverage'], $value['functionCoverage'], $tests, $cacheTokens);
$root->addFile($key, $value['lineCoverage'], $value['functionCoverage'], $tests);
}
} else {
$child = $root->addDirectory($key);
$this->addItems($child, $value, $tests, $cacheTokens);
$this->addItems($child, $value, $tests);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Node/Directory.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ public function addDirectory(string $name): self
return $directory;
}

public function addFile(string $name, array $lineCoverageData, array $functionCoverageData, array $testData, bool $cacheTokens): File
public function addFile(string $name, array $lineCoverageData, array $functionCoverageData, array $testData): File
{
$file = new File($name, $this, $lineCoverageData, $functionCoverageData, $testData, $cacheTokens);
$file = new File($name, $this, $lineCoverageData, $functionCoverageData, $testData);

$this->children[] = $file;
$this->files[] = &$this->children[count($this->children) - 1];
Expand Down
15 changes: 2 additions & 13 deletions src/Node/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use function strpos;
use OutOfBoundsException;
use PHP_Token_Stream;
use PHP_Token_Stream_CachingFactory;

/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
Expand Down Expand Up @@ -123,24 +122,18 @@ final class File extends AbstractNode
*/
private $numTestedFunctions;

/**
* @var bool
*/
private $cacheTokens;

/**
* @var array
*/
private $codeUnitsByLine = [];

public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, bool $cacheTokens)
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData)
{
parent::__construct($name, $parent);

$this->lineCoverageData = $lineCoverageData;
$this->functionCoverageData = $functionCoverageData;
$this->testData = $testData;
$this->cacheTokens = $cacheTokens;

$this->calculateStatistics();
}
Expand Down Expand Up @@ -338,11 +331,7 @@ public function numberOfTestedFunctions(): int

private function calculateStatistics(): void
{
if ($this->cacheTokens) {
$tokens = PHP_Token_Stream_CachingFactory::get($this->pathAsString());
} else {
$tokens = new PHP_Token_Stream($this->pathAsString());
}
$tokens = new PHP_Token_Stream($this->pathAsString());

$this->linesOfCode = $tokens->getLinesOfCode();

Expand Down
Loading