summaryrefslogtreecommitdiff
path: root/vendor/phpunit/php-code-coverage/src/StaticAnalysis
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpunit/php-code-coverage/src/StaticAnalysis')
-rw-r--r--vendor/phpunit/php-code-coverage/src/StaticAnalysis/CachingFileAnalyser.php31
-rw-r--r--vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php3
-rw-r--r--vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php449
-rw-r--r--vendor/phpunit/php-code-coverage/src/StaticAnalysis/IgnoredLinesFindingVisitor.php35
-rw-r--r--vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php68
5 files changed, 349 insertions, 237 deletions
diff --git a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CachingFileAnalyser.php b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CachingFileAnalyser.php
index cdaad5613..f53da078a 100644
--- a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CachingFileAnalyser.php
+++ b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CachingFileAnalyser.php
@@ -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
@@ -50,10 +50,6 @@ final class CachingFileAnalyser implements FileAnalyser
$this->analyser = $analyser;
$this->directory = $directory;
-
- if (self::$cacheVersion === null) {
- $this->calculateCacheVersion();
- }
}
public function classesIn(string $filename): array
@@ -165,19 +161,24 @@ 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);
+ return $this->directory . DIRECTORY_SEPARATOR . md5($filename . "\0" . file_get_contents($filename) . "\0" . self::cacheVersion());
}
- private function calculateCacheVersion(): void
+ private static function cacheVersion(): string
{
- $buffer = '';
+ if (self::$cacheVersion !== null) {
+ return self::$cacheVersion;
+ }
- foreach (new GlobIterator(__DIR__ . '/*.php') as $file) {
- assert($file instanceof SplFileInfo);
+ $buffer = [];
- $buffer .= file_get_contents($file->getPathname());
+ foreach ((new FileIteratorFacade)->getFilesAsArray(__DIR__, '.php') as $file) {
+ $buffer[] = $file;
+ $buffer[] = file_get_contents($file);
}
- self::$cacheVersion = (string) crc32($buffer);
+ self::$cacheVersion = md5(implode("\0", $buffer));
+
+ return self::$cacheVersion;
}
}
diff --git a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php
index 8d357b202..8a2003fa8 100644
--- a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php
+++ b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php
@@ -9,6 +9,7 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
+use function assert;
use function implode;
use function rtrim;
use function trim;
@@ -314,6 +315,8 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
if ($_type instanceof Name) {
$types[] = $_type->toCodeString();
} else {
+ assert($_type instanceof Identifier);
+
$types[] = $_type->toString();
}
}
diff --git a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php
index ae0b08ae7..506f27524 100644
--- a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php
+++ b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ExecutableLinesFindingVisitor.php
@@ -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,337 @@ 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 = [];
- public function enterNode(Node $node): void
+ /**
+ * @var array<int, bool>
+ */
+ private $unsets = [];
+
+ /**
+ * @var array<int, string>
+ */
+ private $commentsToCheckForUnset = [];
+
+ public function __construct(string $source)
{
- $this->savePropertyLines($node);
+ $this->source = $source;
+ }
- if (!$this->isExecutable($node)) {
- return;
- }
+ public function enterNode(Node $node): void
+ {
+ foreach ($node->getComments() as $comment) {
+ $commentLine = $comment->getStartLine();
- foreach ($this->getLines($node) as $line) {
- if (isset($this->propertyLines[$line])) {
- return;
+ if (!isset($this->executableLinesGroupedByBranch[$commentLine])) {
+ continue;
}
- $this->executableLines[$line] = $line;
+ foreach (explode("\n", $comment->getText()) as $text) {
+ $this->commentsToCheckForUnset[$commentLine] = $text;
+ $commentLine++;
+ }
}
- }
- /**
- * @psalm-return array<int, int>
- */
- public function executableLines(): array
- {
- $this->computeReturns();
+ if ($node instanceof Node\Scalar\String_ ||
+ $node instanceof Node\Scalar\EncapsedStringPart) {
+ $startLine = $node->getStartLine() + 1;
+ $endLine = $node->getEndLine() - 1;
- sort($this->executableLines);
+ if ($startLine <= $endLine) {
+ foreach (range($startLine, $endLine) as $line) {
+ unset($this->executableLinesGroupedByBranch[$line]);
+ }
+ }
- return $this->executableLines;
- }
+ return;
+ }
- private function savePropertyLines(Node $node): void
- {
- if (!$node instanceof Property && !$node instanceof Node\Stmt\ClassConst) {
+ 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\Interface_ ||
+ $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\ComplexType ||
+ $node instanceof Node\Const_ ||
+ $node instanceof Node\Identifier ||
+ $node instanceof Node\Name ||
+ $node instanceof Node\Param ||
+ $node instanceof Node\Scalar) {
return;
}
- foreach (range($node->getStartLine(), $node->getEndLine()) as $index) {
- $this->propertyLines[$index] = $index;
+ if ($node instanceof Node\Stmt\Throw_) {
+ $this->setLineBranch($node->expr->getEndLine(), $node->expr->getEndLine(), ++$this->nextBranch);
+
+ return;
}
- }
- private function computeReturns(): void
- {
- foreach ($this->returns as $return) {
- foreach (range($return->getStartLine(), $return->getEndLine()) as $loc) {
- if (isset($this->executableLines[$loc])) {
- continue 2;
+ 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;
+ }
+ }
}
}
- $line = $return->getEndLine();
+ if ($isConcreteClassLike) {
+ return;
+ }
+
+ $hasEmptyBody = [] === $node->stmts ||
+ null === $node->stmts ||
+ (
+ 1 === count($node->stmts) &&
+ $node->stmts[0] instanceof Node\Stmt\Nop
+ );
+
+ if ($hasEmptyBody) {
+ if ($node->getEndLine() === $node->getStartLine()) {
+ return;
+ }
+
+ $this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
- if ($return->expr !== null) {
- $line = $return->expr->getStartLine();
+ return;
}
- $this->executableLines[$line] = $line;
+ return;
}
- }
- /**
- * @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 Node\Expr\ArrowFunction) {
+ $startLine = max(
+ $node->getStartLine() + 1,
+ $node->expr->getStartLine()
+ );
- if ($node instanceof ArrayDimFetch) {
- if (null === $node->dim) {
- return [];
+ $endLine = $node->expr->getEndLine();
+
+ if ($endLine < $startLine) {
+ return;
}
- return [$node->dim->getStartLine()];
+ $this->setLineBranch($startLine, $endLine, ++$this->nextBranch);
+
+ return;
}
- if ($node instanceof Array_) {
- $startLine = $node->getStartLine();
+ 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 (isset($this->executableLines[$startLine])) {
- return [];
+ if ($node->getStartLine() !== $node->else->getEndLine()) {
+ $this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch);
}
- if ([] === $node->items) {
- return [$node->getEndLine()];
+ return;
+ }
+
+ if ($node instanceof Node\Expr\BinaryOp\Coalesce) {
+ if ($node->getStartLine() !== $node->getEndLine()) {
+ $this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
}
- if ($node->items[0] instanceof ArrayItem) {
- return [$node->items[0]->getStartLine()];
+ 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 ClassMethod) {
- if ($node->name->name !== '__construct') {
- 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);
}
- $existsAPromotedProperty = false;
+ if ([] !== $node->cond) {
+ if (null === $startLine) {
+ $startLine = $node->cond[0]->getStartLine();
+ }
+
+ end($node->cond);
+
+ $endLine = current($node->cond)->getEndLine();
- foreach ($node->getParams() as $param) {
- if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) {
- $existsAPromotedProperty = true;
+ reset($node->cond);
+ }
- 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
+ );
- if ($node instanceof MethodCall) {
- return [$node->name->getStartLine()];
+ return;
}
- if ($node instanceof Ternary) {
- $lines = [$node->cond->getStartLine()];
+ if ($node instanceof Node\Stmt\Foreach_) {
+ $this->setLineBranch(
+ $node->expr->getStartLine(),
+ $node->valueVar->getEndLine(),
+ ++$this->nextBranch
+ );
- if (null !== $node->if) {
- $lines[] = $node->if->getStartLine();
- }
+ return;
+ }
- $lines[] = $node->else->getStartLine();
+ if ($node instanceof Node\Stmt\While_ ||
+ $node instanceof Node\Stmt\Do_) {
+ $this->setLineBranch(
+ $node->cond->getStartLine(),
+ $node->cond->getEndLine(),
+ ++$this->nextBranch
+ );
- return $lines;
+ return;
}
- if ($node instanceof Match_) {
- return [$node->cond->getStartLine()];
+ 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 MatchArm) {
- return [$node->body->getStartLine()];
+ if ($node instanceof Node\Expr\CallLike) {
+ if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
+ $branch = $this->executableLinesGroupedByBranch[$node->getStartLine()];
+ } else {
+ $branch = ++$this->nextBranch;
+ }
+
+ $this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch);
+
+ return;
}
- if ($node instanceof Expression && (
- $node->expr instanceof Cast ||
- $node->expr instanceof Match_ ||
- $node->expr instanceof MethodCall
- )) {
- return [];
+ if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
+ return;
}
- if ($node instanceof Return_) {
- $this->returns[] = $node;
+ $this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch);
+ }
+
+ public function afterTraverse(array $nodes): void
+ {
+ $lines = explode("\n", $this->source);
+
+ foreach ($lines as $lineNumber => $line) {
+ $lineNumber++;
- return [];
+ 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]);
+ }
}
- return [$node->getStartLine()];
+ $this->executableLinesGroupedByBranch = array_diff_key(
+ $this->executableLinesGroupedByBranch,
+ $this->unsets
+ );
}
- private function isExecutable(Node $node): bool
+ public function executableLinesGroupedByBranch(): array
{
- 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_;
+ return $this->executableLinesGroupedByBranch;
+ }
+
+ private function setLineBranch(int $start, int $end, int $branch): void
+ {
+ foreach (range($start, $end) as $line) {
+ $this->executableLinesGroupedByBranch[$line] = $branch;
+ }
}
}
diff --git a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/IgnoredLinesFindingVisitor.php b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/IgnoredLinesFindingVisitor.php
index ebb879e84..3c0b2373c 100644
--- a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/IgnoredLinesFindingVisitor.php
+++ b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/IgnoredLinesFindingVisitor.php
@@ -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;
- }
}
diff --git a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php
index 8edf973e2..e68638219 100644
--- a/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php
+++ b/vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php
@@ -9,11 +9,14 @@
*/
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;
@@ -153,7 +156,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 +175,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$filename,
$error->getMessage()
),
- (int) $error->getCode(),
+ $error->getCode(),
$error
);
}
@@ -181,7 +184,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 +209,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]);
-
- if ($comment === '// @codeCoverageIgnore' ||
- $comment === '//@codeCoverageIgnore') {
- $ignore = true;
- $stop = true;
- } elseif ($comment === '// @codeCoverageIgnoreStart' ||
- $comment === '//@codeCoverageIgnoreStart') {
- $ignore = true;
- } elseif ($comment === '// @codeCoverageIgnoreEnd' ||
- $comment === '//@codeCoverageIgnoreEnd') {
- $stop = true;
- }
-
- break;
- }
+ $comment = trim($token[1]);
- 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])
+ );
}
}
}