Aggiornato Composer

This commit is contained in:
Paolo A
2024-05-17 12:24:19 +00:00
parent 4ac62108b5
commit ec201d75b2
2238 changed files with 38684 additions and 59785 deletions

View File

@@ -20,7 +20,9 @@ final class CacheWarmer
new ParsingFileAnalyser(
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode
)
),
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode,
);
foreach ($filter->files() as $file) {

View File

@@ -9,15 +9,15 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function assert;
use function crc32;
use function file_get_contents;
use function file_put_contents;
use function implode;
use function is_file;
use function md5;
use function serialize;
use GlobIterator;
use function unserialize;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
use SplFileInfo;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -29,31 +29,39 @@ final class CachingFileAnalyser implements FileAnalyser
*/
private static $cacheVersion;
/**
* @var string
*/
private $directory;
/**
* @var FileAnalyser
*/
private $analyser;
/**
* @var bool
*/
private $useAnnotationsForIgnoringCode;
/**
* @var bool
*/
private $ignoreDeprecatedCode;
/**
* @var array
*/
private $cache = [];
/**
* @var string
*/
private $directory;
public function __construct(string $directory, FileAnalyser $analyser)
public function __construct(string $directory, FileAnalyser $analyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
{
Filesystem::createDirectory($directory);
$this->analyser = $analyser;
$this->directory = $directory;
if (self::$cacheVersion === null) {
$this->calculateCacheVersion();
}
$this->analyser = $analyser;
$this->directory = $directory;
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
}
public function classesIn(string $filename): array
@@ -165,19 +173,37 @@ final class CachingFileAnalyser implements FileAnalyser
private function cacheFile(string $filename): string
{
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . crc32(file_get_contents($filename)) . self::$cacheVersion);
$cacheKey = md5(
implode(
"\0",
[
$filename,
file_get_contents($filename),
self::cacheVersion(),
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode,
]
)
);
return $this->directory . DIRECTORY_SEPARATOR . $cacheKey;
}
private function calculateCacheVersion(): void
private static function cacheVersion(): string
{
$buffer = '';
foreach (new GlobIterator(__DIR__ . '/*.php') as $file) {
assert($file instanceof SplFileInfo);
$buffer .= file_get_contents($file->getPathname());
if (self::$cacheVersion !== null) {
return self::$cacheVersion;
}
self::$cacheVersion = (string) crc32($buffer);
$buffer = [];
foreach ((new FileIteratorFacade)->getFilesAsArray(__DIR__, '.php') as $file) {
$buffer[] = $file;
$buffer[] = file_get_contents($file);
}
self::$cacheVersion = md5(implode("\0", $buffer));
return self::$cacheVersion;
}
}

View File

@@ -9,6 +9,7 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function assert;
use function implode;
use function rtrim;
use function trim;
@@ -25,6 +26,7 @@ use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\UnionType;
use PhpParser\NodeAbstract;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor;
@@ -179,8 +181,12 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
return '?' . $type->type;
}
if ($type instanceof UnionType || $type instanceof IntersectionType) {
return $this->unionOrIntersectionAsString($type);
if ($type instanceof UnionType) {
return $this->unionTypeAsString($type);
}
if ($type instanceof IntersectionType) {
return $this->intersectionTypeAsString($type);
}
return $type->toString();
@@ -297,27 +303,43 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
return trim(rtrim($namespacedName, $name), '\\');
}
/**
* @psalm-param UnionType|IntersectionType $type
*/
private function unionOrIntersectionAsString(ComplexType $type): string
private function unionTypeAsString(UnionType $node): string
{
if ($type instanceof UnionType) {
$separator = '|';
} else {
$separator = '&';
}
$types = [];
foreach ($type->types as $_type) {
if ($_type instanceof Name) {
$types[] = $_type->toCodeString();
} else {
$types[] = $_type->toString();
foreach ($node->types as $type) {
if ($type instanceof IntersectionType) {
$types[] = '(' . $this->intersectionTypeAsString($type) . ')';
continue;
}
$types[] = $this->typeAsString($type);
}
return implode($separator, $types);
return implode('|', $types);
}
private function intersectionTypeAsString(IntersectionType $node): string
{
$types = [];
foreach ($node->types as $type) {
$types[] = $this->typeAsString($type);
}
return implode('&', $types);
}
/**
* @psalm-param Identifier|Name $node $node
*/
private function typeAsString(NodeAbstract $node): string
{
if ($node instanceof Name) {
return $node->toCodeString();
}
return $node->toString();
}
}

View File

@@ -9,46 +9,19 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_diff_key;
use function assert;
use function count;
use function current;
use function end;
use function explode;
use function max;
use function preg_match;
use function preg_quote;
use function range;
use function reset;
use function sprintf;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Match_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\NullsafePropertyFetch;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\MatchArm;
use PhpParser\Node\Scalar\Encapsed;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
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\Property;
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;
/**
@@ -57,217 +30,361 @@ use PhpParser\NodeVisitorAbstract;
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var array<int, int>
* @var int
*/
private $executableLines = [];
private $nextBranch = 0;
/**
* @psalm-var array<int, int>
* @var string
*/
private $propertyLines = [];
private $source;
/**
* @psalm-var array<int, Return_>
* @var array<int, int>
*/
private $returns = [];
private $executableLinesGroupedByBranch = [];
/**
* @var array<int, bool>
*/
private $unsets = [];
/**
* @var array<int, string>
*/
private $commentsToCheckForUnset = [];
public function __construct(string $source)
{
$this->source = $source;
}
public function enterNode(Node $node): void
{
$this->savePropertyLines($node);
foreach ($node->getComments() as $comment) {
$commentLine = $comment->getStartLine();
if (!isset($this->executableLinesGroupedByBranch[$commentLine])) {
continue;
}
foreach (explode("\n", $comment->getText()) as $text) {
$this->commentsToCheckForUnset[$commentLine] = $text;
$commentLine++;
}
}
if ($node instanceof Node\Scalar\String_ ||
$node instanceof Node\Scalar\EncapsedStringPart) {
$startLine = $node->getStartLine() + 1;
$endLine = $node->getEndLine() - 1;
if ($startLine <= $endLine) {
foreach (range($startLine, $endLine) as $line) {
unset($this->executableLinesGroupedByBranch[$line]);
}
}
if (!$this->isExecutable($node)) {
return;
}
foreach ($this->getLines($node) as $line) {
if (isset($this->propertyLines[$line])) {
if ($node instanceof Node\Stmt\Interface_) {
foreach (range($node->getStartLine(), $node->getEndLine()) as $line) {
$this->unsets[$line] = true;
}
return;
}
if ($node instanceof Node\Stmt\Declare_ ||
$node instanceof Node\Stmt\DeclareDeclare ||
$node instanceof Node\Stmt\Else_ ||
$node instanceof Node\Stmt\EnumCase ||
$node instanceof Node\Stmt\Finally_ ||
$node instanceof Node\Stmt\GroupUse ||
$node instanceof Node\Stmt\Label ||
$node instanceof Node\Stmt\Namespace_ ||
$node instanceof Node\Stmt\Nop ||
$node instanceof Node\Stmt\Switch_ ||
$node instanceof Node\Stmt\TryCatch ||
$node instanceof Node\Stmt\Use_ ||
$node instanceof Node\Stmt\UseUse ||
$node instanceof Node\Expr\ConstFetch ||
$node instanceof Node\Expr\Match_ ||
$node instanceof Node\Expr\Variable ||
$node instanceof Node\Expr\Throw_ ||
$node instanceof Node\ComplexType ||
$node instanceof Node\Const_ ||
$node instanceof Node\Identifier ||
$node instanceof Node\Name ||
$node instanceof Node\Param ||
$node instanceof Node\Scalar) {
return;
}
/*
* nikic/php-parser ^4.18 represents <code>throw</code> statements
* as <code>Stmt\Throw_</code> objects
*/
if ($node instanceof Node\Stmt\Throw_) {
$this->setLineBranch($node->expr->getEndLine(), $node->expr->getEndLine(), ++$this->nextBranch);
return;
}
/*
* nikic/php-parser ^5 represents <code>throw</code> statements
* as <code>Stmt\Expression</code> objects that contain an
* <code>Expr\Throw_</code> object
*/
if ($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Throw_) {
$this->setLineBranch($node->expr->expr->getEndLine(), $node->expr->expr->getEndLine(), ++$this->nextBranch);
return;
}
if ($node instanceof Node\Stmt\Enum_ ||
$node instanceof Node\Stmt\Function_ ||
$node instanceof Node\Stmt\Class_ ||
$node instanceof Node\Stmt\ClassMethod ||
$node instanceof Node\Expr\Closure ||
$node instanceof Node\Stmt\Trait_) {
$isConcreteClassLike = $node instanceof Node\Stmt\Enum_ || $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_;
if (null !== $node->stmts) {
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Node\Stmt\Nop) {
continue;
}
foreach (range($stmt->getStartLine(), $stmt->getEndLine()) as $line) {
unset($this->executableLinesGroupedByBranch[$line]);
if (
$isConcreteClassLike &&
!$stmt instanceof Node\Stmt\ClassMethod
) {
$this->unsets[$line] = true;
}
}
}
}
if ($isConcreteClassLike) {
return;
}
$this->executableLines[$line] = $line;
}
}
$hasEmptyBody = [] === $node->stmts ||
null === $node->stmts ||
(
1 === count($node->stmts) &&
$node->stmts[0] instanceof Node\Stmt\Nop
);
/**
* @psalm-return array<int, int>
*/
public function executableLines(): array
{
$this->computeReturns();
if ($hasEmptyBody) {
if ($node->getEndLine() === $node->getStartLine()) {
return;
}
sort($this->executableLines);
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
return $this->executableLines;
}
return;
}
private function savePropertyLines(Node $node): void
{
if (!$node instanceof Property && !$node instanceof Node\Stmt\ClassConst) {
return;
}
foreach (range($node->getStartLine(), $node->getEndLine()) as $index) {
$this->propertyLines[$index] = $index;
}
}
if ($node instanceof Node\Expr\ArrowFunction) {
$startLine = max(
$node->getStartLine() + 1,
$node->expr->getStartLine()
);
private function computeReturns(): void
{
foreach ($this->returns as $return) {
foreach (range($return->getStartLine(), $return->getEndLine()) as $loc) {
if (isset($this->executableLines[$loc])) {
continue 2;
$endLine = $node->expr->getEndLine();
if ($endLine < $startLine) {
return;
}
$this->setLineBranch($startLine, $endLine, ++$this->nextBranch);
return;
}
if ($node instanceof Node\Expr\Ternary) {
if (null !== $node->if &&
$node->getStartLine() !== $node->if->getEndLine()) {
$this->setLineBranch($node->if->getStartLine(), $node->if->getEndLine(), ++$this->nextBranch);
}
if ($node->getStartLine() !== $node->else->getEndLine()) {
$this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch);
}
return;
}
if ($node instanceof Node\Expr\BinaryOp\Coalesce) {
if ($node->getStartLine() !== $node->getEndLine()) {
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
}
return;
}
if ($node instanceof Node\Stmt\If_ ||
$node instanceof Node\Stmt\ElseIf_ ||
$node instanceof Node\Stmt\Case_) {
if (null === $node->cond) {
return;
}
$this->setLineBranch(
$node->cond->getStartLine(),
$node->cond->getStartLine(),
++$this->nextBranch
);
return;
}
if ($node instanceof Node\Stmt\For_) {
$startLine = null;
$endLine = null;
if ([] !== $node->init) {
$startLine = $node->init[0]->getStartLine();
end($node->init);
$endLine = current($node->init)->getEndLine();
reset($node->init);
}
if ([] !== $node->cond) {
if (null === $startLine) {
$startLine = $node->cond[0]->getStartLine();
}
end($node->cond);
$endLine = current($node->cond)->getEndLine();
reset($node->cond);
}
$line = $return->getEndLine();
if ($return->expr !== null) {
$line = $return->expr->getStartLine();
}
$this->executableLines[$line] = $line;
}
}
/**
* @return int[]
*/
private function getLines(Node $node): array
{
if ($node instanceof Cast ||
$node instanceof PropertyFetch ||
$node instanceof NullsafePropertyFetch ||
$node instanceof StaticPropertyFetch) {
return [$node->getEndLine()];
}
if ($node instanceof ArrayDimFetch) {
if (null === $node->dim) {
return [];
}
return [$node->dim->getStartLine()];
}
if ($node instanceof Array_) {
$startLine = $node->getStartLine();
if (isset($this->executableLines[$startLine])) {
return [];
}
if ([] === $node->items) {
return [$node->getEndLine()];
}
if ($node->items[0] instanceof ArrayItem) {
return [$node->items[0]->getStartLine()];
}
}
if ($node instanceof ClassMethod) {
if ($node->name->name !== '__construct') {
return [];
}
$existsAPromotedProperty = false;
foreach ($node->getParams() as $param) {
if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) {
$existsAPromotedProperty = true;
break;
if ([] !== $node->loop) {
if (null === $startLine) {
$startLine = $node->loop[0]->getStartLine();
}
end($node->loop);
$endLine = current($node->loop)->getEndLine();
reset($node->loop);
}
if ($existsAPromotedProperty) {
// Only the line with `function` keyword should be listed here
// but `nikic/php-parser` doesn't provide a way to fetch it
return range($node->getStartLine(), $node->name->getEndLine());
if (null === $startLine || null === $endLine) {
return;
}
return [];
$this->setLineBranch(
$startLine,
$endLine,
++$this->nextBranch
);
return;
}
if ($node instanceof MethodCall) {
return [$node->name->getStartLine()];
if ($node instanceof Node\Stmt\Foreach_) {
$this->setLineBranch(
$node->expr->getStartLine(),
$node->valueVar->getEndLine(),
++$this->nextBranch
);
return;
}
if ($node instanceof Ternary) {
$lines = [$node->cond->getStartLine()];
if ($node instanceof Node\Stmt\While_ ||
$node instanceof Node\Stmt\Do_) {
$this->setLineBranch(
$node->cond->getStartLine(),
$node->cond->getEndLine(),
++$this->nextBranch
);
if (null !== $node->if) {
$lines[] = $node->if->getStartLine();
return;
}
if ($node instanceof Node\Stmt\Catch_) {
assert([] !== $node->types);
$startLine = $node->types[0]->getStartLine();
end($node->types);
$endLine = current($node->types)->getEndLine();
$this->setLineBranch(
$startLine,
$endLine,
++$this->nextBranch
);
return;
}
if ($node instanceof Node\Expr\CallLike) {
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
$branch = $this->executableLinesGroupedByBranch[$node->getStartLine()];
} else {
$branch = ++$this->nextBranch;
}
$lines[] = $node->else->getStartLine();
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch);
return $lines;
return;
}
if ($node instanceof Match_) {
return [$node->cond->getStartLine()];
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
return;
}
if ($node instanceof MatchArm) {
return [$node->body->getStartLine()];
}
if ($node instanceof Expression && (
$node->expr instanceof Cast ||
$node->expr instanceof Match_ ||
$node->expr instanceof MethodCall
)) {
return [];
}
if ($node instanceof Return_) {
$this->returns[] = $node;
return [];
}
return [$node->getStartLine()];
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch);
}
private function isExecutable(Node $node): bool
public function afterTraverse(array $nodes): void
{
return $node instanceof Assign ||
$node instanceof ArrayDimFetch ||
$node instanceof Array_ ||
$node instanceof BinaryOp ||
$node instanceof Break_ ||
$node instanceof CallLike ||
$node instanceof Case_ ||
$node instanceof Cast ||
$node instanceof Catch_ ||
$node instanceof ClassMethod ||
$node instanceof Closure ||
$node instanceof Continue_ ||
$node instanceof Do_ ||
$node instanceof Echo_ ||
$node instanceof ElseIf_ ||
$node instanceof Else_ ||
$node instanceof Encapsed ||
$node instanceof Expression ||
$node instanceof Finally_ ||
$node instanceof For_ ||
$node instanceof Foreach_ ||
$node instanceof Goto_ ||
$node instanceof If_ ||
$node instanceof Match_ ||
$node instanceof MatchArm ||
$node instanceof MethodCall ||
$node instanceof NullsafePropertyFetch ||
$node instanceof PropertyFetch ||
$node instanceof Return_ ||
$node instanceof StaticPropertyFetch ||
$node instanceof Switch_ ||
$node instanceof Ternary ||
$node instanceof Throw_ ||
$node instanceof TryCatch ||
$node instanceof Unset_ ||
$node instanceof While_;
$lines = explode("\n", $this->source);
foreach ($lines as $lineNumber => $line) {
$lineNumber++;
if (1 === preg_match('/^\s*$/', $line) ||
(
isset($this->commentsToCheckForUnset[$lineNumber]) &&
1 === preg_match(sprintf('/^\s*%s\s*$/', preg_quote($this->commentsToCheckForUnset[$lineNumber], '/')), $line)
)) {
unset($this->executableLinesGroupedByBranch[$lineNumber]);
}
}
$this->executableLinesGroupedByBranch = array_diff_key(
$this->executableLinesGroupedByBranch,
$this->unsets
);
}
public function executableLinesGroupedByBranch(): array
{
return $this->executableLinesGroupedByBranch;
}
private function setLineBranch(int $start, int $end, int $branch): void
{
foreach (range($start, $end) as $line) {
$this->executableLinesGroupedByBranch[$line] = $branch;
}
}
}

View File

@@ -10,9 +10,11 @@
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_merge;
use function assert;
use function range;
use function strpos;
use PhpParser\Node;
use PhpParser\Node\Attribute;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
@@ -52,7 +54,8 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
!$node instanceof Trait_ &&
!$node instanceof Interface_ &&
!$node instanceof ClassMethod &&
!$node instanceof Function_) {
!$node instanceof Function_ &&
!$node instanceof Attribute) {
return;
}
@@ -60,11 +63,16 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
return;
}
// Workaround for https://bugs.xdebug.org/view.php?id=1798
if ($node instanceof Class_ ||
$node instanceof Trait_ ||
$node instanceof Interface_) {
$node instanceof Interface_ ||
$node instanceof Attribute) {
$this->ignoredLines[] = $node->getStartLine();
assert($node->name !== null);
// Workaround for https://github.com/nikic/PHP-Parser/issues/886
$this->ignoredLines[] = $node->name->getStartLine();
}
if (!$this->useAnnotationsForIgnoringCode) {
@@ -75,6 +83,19 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
return;
}
$this->processDocComment($node);
}
/**
* @psalm-return list<int>
*/
public function ignoredLines(): array
{
return $this->ignoredLines;
}
private function processDocComment(Node $node): void
{
$docComment = $node->getDocComment();
if ($docComment === null) {
@@ -95,12 +116,4 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
);
}
}
/**
* @psalm-return list<int>
*/
public function ignoredLines(): array
{
return $this->ignoredLines;
}
}

View File

@@ -9,17 +9,19 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_merge;
use function array_unique;
use function assert;
use function file_get_contents;
use function is_array;
use function max;
use function range;
use function sort;
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;
@@ -139,10 +141,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$linesOfCode = 1;
}
$parser = (new ParserFactory)->create(
ParserFactory::PREFER_PHP7,
new Lexer
);
$parser = (new ParserFactory)->createForHostVersion();
try {
$nodes = $parser->parse($source);
@@ -153,7 +152,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor;
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($source);
$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ParentConnectingVisitor);
@@ -172,7 +171,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$filename,
$error->getMessage()
),
(int) $error->getCode(),
$error->getCode(),
$error
);
}
@@ -181,7 +180,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLines();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLinesGroupedByBranch();
$this->ignoredLines[$filename] = [];
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
@@ -206,45 +205,44 @@ final class ParsingFileAnalyser implements FileAnalyser
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void
{
$ignore = false;
$stop = false;
if (!$useAnnotationsForIgnoringCode) {
return;
}
$start = false;
foreach (token_get_all($source) as $token) {
if (!is_array($token)) {
if (!is_array($token) ||
!(T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0])) {
continue;
}
switch ($token[0]) {
case T_COMMENT:
case T_DOC_COMMENT:
if (!$useAnnotationsForIgnoringCode) {
break;
}
$comment = trim($token[1]);
$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) {
if ($comment === '// @codeCoverageIgnore' ||
$comment === '//@codeCoverageIgnore') {
$this->ignoredLines[$filename][] = $token[2];
if ($stop) {
$ignore = false;
$stop = false;
continue;
}
if ($comment === '// @codeCoverageIgnoreStart' ||
$comment === '//@codeCoverageIgnoreStart') {
$start = $token[2];
continue;
}
if ($comment === '// @codeCoverageIgnoreEnd' ||
$comment === '//@codeCoverageIgnoreEnd') {
if (false === $start) {
$start = $token[2];
}
$this->ignoredLines[$filename] = array_merge(
$this->ignoredLines[$filename],
range($start, $token[2])
);
}
}
}