upgrade to laravel 8.x

This commit is contained in:
2021-05-30 08:20:41 +00:00
parent 41b78a0599
commit 3ad6ed8bfa
2333 changed files with 113904 additions and 59058 deletions
@@ -0,0 +1,90 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use const DIRECTORY_SEPARATOR;
use function file_get_contents;
use function file_put_contents;
use function filemtime;
use function hash;
use function is_file;
use function serialize;
use function unserialize;
use SebastianBergmann\CodeCoverage\Directory;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
abstract class Cache
{
/**
* @var string
*/
private $directory;
public function __construct(string $directory)
{
Directory::create($directory);
$this->directory = $directory;
}
protected function has(string $filename, string $key): bool
{
$cacheFile = $this->cacheFile($filename, $key);
if (!is_file($cacheFile)) {
return false;
}
if (filemtime($cacheFile) < filemtime($filename)) {
return false;
}
return true;
}
/**
* @psalm-param list<class-string> $allowedClasses
*
* @return mixed
*/
protected function read(string $filename, string $key, array $allowedClasses = [])
{
$options = ['allowed_classes' => false];
if (!empty($allowedClasses)) {
$options = ['allowed_classes' => $allowedClasses];
}
return unserialize(
file_get_contents(
$this->cacheFile($filename, $key)
),
$options
);
}
/**
* @param mixed $data
*/
protected function write(string $filename, string $key, $data): void
{
file_put_contents(
$this->cacheFile($filename, $key),
serialize($data)
);
}
private function cacheFile(string $filename, string $key): string
{
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . $key);
}
}
@@ -0,0 +1,38 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use SebastianBergmann\CodeCoverage\Filter;
final class CacheWarmer
{
public function warmCache(string $cacheDirectory, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode, Filter $filter): void
{
$coveredFileAnalyser = new CachingCoveredFileAnalyser(
$cacheDirectory,
new ParsingCoveredFileAnalyser(
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode
)
);
$uncoveredFileAnalyser = new CachingUncoveredFileAnalyser(
$cacheDirectory,
new ParsingUncoveredFileAnalyser
);
foreach ($filter->files() as $file) {
$coveredFileAnalyser->process($file);
/* @noinspection UnusedFunctionResultInspection */
$uncoveredFileAnalyser->executableLinesIn($file);
}
}
}
@@ -0,0 +1,99 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CachingCoveredFileAnalyser extends Cache implements CoveredFileAnalyser
{
/**
* @var CoveredFileAnalyser
*/
private $coveredFileAnalyser;
/**
* @var array
*/
private $cache = [];
public function __construct(string $directory, CoveredFileAnalyser $coveredFileAnalyser)
{
parent::__construct($directory);
$this->coveredFileAnalyser = $coveredFileAnalyser;
}
public function classesIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['classesIn'];
}
public function traitsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['traitsIn'];
}
public function functionsIn(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['functionsIn'];
}
public function linesOfCodeFor(string $filename): LinesOfCode
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['linesOfCodeFor'];
}
public function ignoredLinesFor(string $filename): array
{
if (!isset($this->cache[$filename])) {
$this->process($filename);
}
return $this->cache[$filename]['ignoredLinesFor'];
}
public function process(string $filename): void
{
if ($this->has($filename, __CLASS__)) {
$this->cache[$filename] = $this->read($filename, __CLASS__, [LinesOfCode::class]);
return;
}
$this->cache[$filename] = [
'classesIn' => $this->coveredFileAnalyser->classesIn($filename),
'traitsIn' => $this->coveredFileAnalyser->traitsIn($filename),
'functionsIn' => $this->coveredFileAnalyser->functionsIn($filename),
'linesOfCodeFor' => $this->coveredFileAnalyser->linesOfCodeFor($filename),
'ignoredLinesFor' => $this->coveredFileAnalyser->ignoredLinesFor($filename),
];
$this->write($filename, __CLASS__, $this->cache[$filename]);
}
}
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CachingUncoveredFileAnalyser extends Cache implements UncoveredFileAnalyser
{
/**
* @var UncoveredFileAnalyser
*/
private $uncoveredFileAnalyser;
public function __construct(string $directory, UncoveredFileAnalyser $uncoveredFileAnalyser)
{
parent::__construct($directory);
$this->uncoveredFileAnalyser = $uncoveredFileAnalyser;
}
public function executableLinesIn(string $filename): array
{
if ($this->has($filename, __METHOD__)) {
return $this->read($filename, __METHOD__);
}
$data = $this->uncoveredFileAnalyser->executableLinesIn($filename);
$this->write($filename, __METHOD__, $data);
return $data;
}
}
@@ -0,0 +1,293 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function implode;
use function rtrim;
use function trim;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\UnionType;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class CodeUnitFindingVisitor extends NodeVisitorAbstract
{
/**
* @var array
*/
private $classes = [];
/**
* @var array
*/
private $traits = [];
/**
* @var array
*/
private $functions = [];
public function enterNode(Node $node)
{
if ($node instanceof Class_) {
if ($node->isAnonymous()) {
return;
}
$this->processClass($node);
}
if ($node instanceof Trait_) {
$this->processTrait($node);
}
if (!$node instanceof ClassMethod && !$node instanceof Function_) {
return null;
}
if ($node instanceof ClassMethod) {
$parentNode = $node->getAttribute('parent');
if ($parentNode instanceof Class_ && $parentNode->isAnonymous()) {
return;
}
$this->processMethod($node);
return;
}
$this->processFunction($node);
}
public function classes(): array
{
return $this->classes;
}
public function traits(): array
{
return $this->traits;
}
public function functions(): array
{
return $this->functions;
}
/**
* @psalm-param ClassMethod|Function_ $node
*/
private function cyclomaticComplexity(Node $node): int
{
assert($node instanceof ClassMethod || $node instanceof Function_);
$nodes = $node->getStmts();
if ($nodes === null) {
return 0;
}
$traverser = new NodeTraverser;
$cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor;
$traverser->addVisitor($cyclomaticComplexityCalculatingVisitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity();
}
/**
* @psalm-param ClassMethod|Function_ $node
*/
private function signature(Node $node): string
{
assert($node instanceof ClassMethod || $node instanceof Function_);
$signature = ($node->returnsByRef() ? '&' : '') . $node->name->toString() . '(';
$parameters = [];
foreach ($node->getParams() as $parameter) {
assert(isset($parameter->var->name));
$parameterAsString = '';
if ($parameter->type !== null) {
$parameterAsString = $this->type($parameter->type) . ' ';
}
$parameterAsString .= '$' . $parameter->var->name;
/* @todo Handle default values */
$parameters[] = $parameterAsString;
}
$signature .= implode(', ', $parameters) . ')';
$returnType = $node->getReturnType();
if ($returnType !== null) {
$signature .= ': ' . $this->type($returnType);
}
return $signature;
}
/**
* @psalm-param Identifier|Name|NullableType|UnionType $type
*/
private function type(Node $type): string
{
assert($type instanceof Identifier || $type instanceof Name || $type instanceof NullableType || $type instanceof UnionType);
if ($type instanceof NullableType) {
return '?' . $type->type;
}
if ($type instanceof UnionType) {
$types = [];
foreach ($type->types as $_type) {
$types[] = $_type->toString();
}
return implode('|', $types);
}
return $type->toString();
}
private function visibility(ClassMethod $node): string
{
if ($node->isPrivate()) {
return 'private';
}
if ($node->isProtected()) {
return 'protected';
}
return 'public';
}
private function processClass(Class_ $node): void
{
$name = $node->name->toString();
$namespacedName = $node->namespacedName->toString();
$this->classes[$namespacedName] = [
'name' => $name,
'namespacedName' => $namespacedName,
'namespace' => $this->namespace($namespacedName, $name),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),
'methods' => [],
];
}
private function processTrait(Trait_ $node): void
{
$name = $node->name->toString();
$namespacedName = $node->namespacedName->toString();
$this->traits[$namespacedName] = [
'name' => $name,
'namespacedName' => $namespacedName,
'namespace' => $this->namespace($namespacedName, $name),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),
'methods' => [],
];
}
private function processMethod(ClassMethod $node): void
{
$parentNode = $node->getAttribute('parent');
if ($parentNode instanceof Interface_) {
return;
}
assert($parentNode instanceof Class_ || $parentNode instanceof Trait_);
assert(isset($parentNode->name));
assert(isset($parentNode->namespacedName));
assert($parentNode->namespacedName instanceof Name);
$parentName = $parentNode->name->toString();
$parentNamespacedName = $parentNode->namespacedName->toString();
if ($parentNode instanceof Class_) {
$storage = &$this->classes;
} else {
$storage = &$this->traits;
}
if (!isset($storage[$parentNamespacedName])) {
$storage[$parentNamespacedName] = [
'name' => $parentName,
'namespacedName' => $parentNamespacedName,
'namespace' => $this->namespace($parentNamespacedName, $parentName),
'startLine' => $parentNode->getStartLine(),
'endLine' => $parentNode->getEndLine(),
'methods' => [],
];
}
$storage[$parentNamespacedName]['methods'][$node->name->toString()] = [
'methodName' => $node->name->toString(),
'signature' => $this->signature($node),
'visibility' => $this->visibility($node),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),
'ccn' => $this->cyclomaticComplexity($node),
];
}
private function processFunction(Function_ $node): void
{
assert(isset($node->name));
assert(isset($node->namespacedName));
assert($node->namespacedName instanceof Name);
$name = $node->name->toString();
$namespacedName = $node->namespacedName->toString();
$this->functions[$namespacedName] = [
'name' => $name,
'namespacedName' => $namespacedName,
'namespace' => $this->namespace($namespacedName, $name),
'signature' => $this->signature($node),
'startLine' => $node->getStartLine(),
'endLine' => $node->getEndLine(),
'ccn' => $this->cyclomaticComplexity($node),
];
}
private function namespace(string $namespacedName, string $name): string
{
return trim(rtrim($namespacedName, $name), '\\');
}
}
@@ -0,0 +1,28 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
interface CoveredFileAnalyser
{
public function classesIn(string $filename): array;
public function traitsIn(string $filename): array;
public function functionsIn(string $filename): array;
public function linesOfCodeFor(string $filename): LinesOfCode;
public function ignoredLinesFor(string $filename): array;
}
@@ -0,0 +1,91 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_unique;
use function sort;
use PhpParser\Node;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\Continue_;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\Echo_;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\ElseIf_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Finally_;
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Goto_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Throw_;
use PhpParser\Node\Stmt\TryCatch;
use PhpParser\Node\Stmt\Unset_;
use PhpParser\Node\Stmt\While_;
use PhpParser\NodeVisitorAbstract;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var list<int>
*/
private $executableLines = [];
public function enterNode(Node $node): void
{
if (!$this->isExecutable($node)) {
return;
}
$this->executableLines[] = $node->getStartLine();
}
/**
* @psalm-return list<int>
*/
public function executableLines(): array
{
$executableLines = array_unique($this->executableLines);
sort($executableLines);
return $executableLines;
}
private function isExecutable(Node $node): bool
{
return $node instanceof Break_ ||
$node instanceof Case_ ||
$node instanceof Catch_ ||
$node instanceof Continue_ ||
$node instanceof Do_ ||
$node instanceof Echo_ ||
$node instanceof ElseIf_ ||
$node instanceof Else_ ||
$node instanceof Expression ||
$node instanceof Finally_ ||
$node instanceof Foreach_ ||
$node instanceof For_ ||
$node instanceof Goto_ ||
$node instanceof If_ ||
$node instanceof Return_ ||
$node instanceof Switch_ ||
$node instanceof Throw_ ||
$node instanceof TryCatch ||
$node instanceof Unset_ ||
$node instanceof While_;
}
}
@@ -0,0 +1,113 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_merge;
use function range;
use function strpos;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var list<int>
*/
private $ignoredLines = [];
/**
* @var bool
*/
private $useAnnotationsForIgnoringCode;
/**
* @var bool
*/
private $ignoreDeprecated;
public function __construct(bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecated)
{
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecated = $ignoreDeprecated;
}
public function enterNode(Node $node): ?int
{
if (!$node instanceof Class_ &&
!$node instanceof Trait_ &&
!$node instanceof Interface_ &&
!$node instanceof ClassMethod &&
!$node instanceof Function_) {
return null;
}
if ($node instanceof Class_ && $node->isAnonymous()) {
return null;
}
// Workaround for https://bugs.xdebug.org/view.php?id=1798
if ($node instanceof Class_ ||
$node instanceof Trait_ ||
$node instanceof Interface_) {
$this->ignoredLines[] = $node->getStartLine();
}
if (!$this->useAnnotationsForIgnoringCode) {
return null;
}
if ($node instanceof Interface_) {
return null;
}
$docComment = $node->getDocComment();
if ($docComment === null) {
return null;
}
if (strpos($docComment->getText(), '@codeCoverageIgnore') !== false) {
$this->ignoredLines = array_merge(
$this->ignoredLines,
range($node->getStartLine(), $node->getEndLine())
);
}
if ($this->ignoreDeprecated && strpos($docComment->getText(), '@deprecated') !== false) {
$this->ignoredLines = array_merge(
$this->ignoredLines,
range($node->getStartLine(), $node->getEndLine())
);
}
if ($node instanceof ClassMethod || $node instanceof Function_) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
return null;
}
/**
* @psalm-return list<int>
*/
public function ignoredLines(): array
{
return $this->ignoredLines;
}
}
@@ -0,0 +1,226 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_unique;
use function assert;
use function file_get_contents;
use function is_array;
use function sprintf;
use function substr_count;
use function token_get_all;
use function trim;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\NodeVisitor\ParentConnectingVisitor;
use PhpParser\ParserFactory;
use SebastianBergmann\CodeCoverage\ParserException;
use SebastianBergmann\LinesOfCode\LineCountingVisitor;
use SebastianBergmann\LinesOfCode\LinesOfCode;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class ParsingCoveredFileAnalyser implements CoveredFileAnalyser
{
/**
* @var array
*/
private $classes = [];
/**
* @var array
*/
private $traits = [];
/**
* @var array
*/
private $functions = [];
/**
* @var LinesOfCode[]
*/
private $linesOfCode = [];
/**
* @var array
*/
private $ignoredLines = [];
/**
* @var bool
*/
private $useAnnotationsForIgnoringCode;
/**
* @var bool
*/
private $ignoreDeprecatedCode;
public function __construct(bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
{
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
}
public function classesIn(string $filename): array
{
$this->analyse($filename);
return $this->classes[$filename];
}
public function traitsIn(string $filename): array
{
$this->analyse($filename);
return $this->traits[$filename];
}
public function functionsIn(string $filename): array
{
$this->analyse($filename);
return $this->functions[$filename];
}
public function linesOfCodeFor(string $filename): LinesOfCode
{
$this->analyse($filename);
return $this->linesOfCode[$filename];
}
public function ignoredLinesFor(string $filename): array
{
$this->analyse($filename);
return $this->ignoredLines[$filename];
}
/**
* @throws ParserException
*/
private function analyse(string $filename): void
{
if (isset($this->classes[$filename])) {
return;
}
$source = file_get_contents($filename);
$linesOfCode = substr_count($source, "\n");
if ($linesOfCode === 0 && !empty($source)) {
$linesOfCode = 1;
}
$parser = (new ParserFactory)->create(
ParserFactory::PREFER_PHP7,
new Lexer
);
try {
$nodes = $parser->parse($source);
assert($nodes !== null);
$traverser = new NodeTraverser;
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ParentConnectingVisitor);
$traverser->addVisitor($codeUnitFindingVisitor);
$traverser->addVisitor($lineCountingVisitor);
$traverser->addVisitor($ignoredLinesFindingVisitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
// @codeCoverageIgnoreStart
} catch (Error $error) {
throw new ParserException(
sprintf(
'Cannot parse %s: %s',
$filename,
$error->getMessage()
),
(int) $error->getCode(),
$error
);
}
// @codeCoverageIgnoreEnd
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->linesOfCode[$filename] = $lineCountingVisitor->result();
$this->ignoredLines[$filename] = [];
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
$this->ignoredLines[$filename] = array_unique(
array_merge(
$this->ignoredLines[$filename],
$ignoredLinesFindingVisitor->ignoredLines()
)
);
sort($this->ignoredLines[$filename]);
}
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void
{
$ignore = false;
$stop = false;
foreach (token_get_all($source) as $token) {
if (!is_array($token)) {
continue;
}
switch ($token[0]) {
case T_COMMENT:
case T_DOC_COMMENT:
if (!$useAnnotationsForIgnoringCode) {
break;
}
$comment = trim($token[1]);
if ($comment === '// @codeCoverageIgnore' ||
$comment === '//@codeCoverageIgnore') {
$ignore = true;
$stop = true;
} elseif ($comment === '// @codeCoverageIgnoreStart' ||
$comment === '//@codeCoverageIgnoreStart') {
$ignore = true;
} elseif ($comment === '// @codeCoverageIgnoreEnd' ||
$comment === '//@codeCoverageIgnoreEnd') {
$stop = true;
}
break;
}
if ($ignore) {
$this->ignoredLines[$filename][] = $token[2];
if ($stop) {
$ignore = false;
$stop = false;
}
}
}
}
}
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
final class ParsingUncoveredFileAnalyser implements UncoveredFileAnalyser
{
public function executableLinesIn(string $filename): array
{
$parser = (new ParserFactory)->create(
ParserFactory::PREFER_PHP7,
new Lexer
);
try {
$nodes = $parser->parse(file_get_contents($filename));
assert($nodes !== null);
$traverser = new NodeTraverser;
$visitor = new ExecutableLinesFindingVisitor;
$traverser->addVisitor($visitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
return $visitor->executableLines();
// @codeCoverageIgnoreStart
} catch (Error $error) {
}
// @codeCoverageIgnoreEnd
return [];
}
}
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-code-coverage.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
*/
interface UncoveredFileAnalyser
{
public function executableLinesIn(string $filename): array;
}