Buckets:
ktongue/docker_container / SGAE /vendor /phpunit /php-code-coverage /src /StaticAnalysis /ExecutableLinesFindingVisitor.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_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\NodeVisitorAbstract; | |
| /** | |
| * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage | |
| * | |
| * @psalm-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser | |
| */ | |
| final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract | |
| { | |
| private int $nextBranch = 0; | |
| private readonly string $source; | |
| /** | |
| * @psalm-var LinesType | |
| */ | |
| private array $executableLinesGroupedByBranch = []; | |
| /** | |
| * @psalm-var array<int, bool> | |
| */ | |
| private array $unsets = []; | |
| /** | |
| * @psalm-var array<int, string> | |
| */ | |
| private array $commentsToCheckForUnset = []; | |
| public function __construct(string $source) | |
| { | |
| $this->source = $source; | |
| } | |
| public function enterNode(Node $node): void | |
| { | |
| 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]); | |
| } | |
| } | |
| return; | |
| } | |
| 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\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; | |
| } | |
| if ($node instanceof Node\Expr\Match_) { | |
| foreach ($node->arms as $arm) { | |
| $this->setLineBranch( | |
| $arm->body->getStartLine(), | |
| $arm->body->getEndLine(), | |
| ++$this->nextBranch, | |
| ); | |
| } | |
| 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_) { | |
| if ($node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\ClassMethod) { | |
| $unsets = []; | |
| foreach ($node->getParams() as $param) { | |
| foreach (range($param->getStartLine(), $param->getEndLine()) as $line) { | |
| $unsets[$line] = true; | |
| } | |
| } | |
| unset($unsets[$node->getEndLine()]); | |
| $this->unsets += $unsets; | |
| } | |
| $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; | |
| } | |
| $hasEmptyBody = [] === $node->stmts || | |
| null === $node->stmts || | |
| ( | |
| 1 === count($node->stmts) && | |
| $node->stmts[0] instanceof Node\Stmt\Nop | |
| ); | |
| if ($hasEmptyBody) { | |
| if ($node->getEndLine() === $node->getStartLine() && isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) { | |
| return; | |
| } | |
| $this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch); | |
| return; | |
| } | |
| return; | |
| } | |
| if ($node instanceof Node\Expr\ArrowFunction) { | |
| $startLine = max( | |
| $node->getStartLine() + 1, | |
| $node->expr->getStartLine(), | |
| ); | |
| $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); | |
| } | |
| if ([] !== $node->loop) { | |
| if (null === $startLine) { | |
| $startLine = $node->loop[0]->getStartLine(); | |
| } | |
| end($node->loop); | |
| $endLine = current($node->loop)->getEndLine(); | |
| reset($node->loop); | |
| } | |
| if (null === $startLine || null === $endLine) { | |
| return; | |
| } | |
| $this->setLineBranch( | |
| $startLine, | |
| $endLine, | |
| ++$this->nextBranch, | |
| ); | |
| return; | |
| } | |
| if ($node instanceof Node\Stmt\Foreach_) { | |
| $this->setLineBranch( | |
| $node->expr->getStartLine(), | |
| $node->valueVar->getEndLine(), | |
| ++$this->nextBranch, | |
| ); | |
| return; | |
| } | |
| if ($node instanceof Node\Stmt\While_ || | |
| $node instanceof Node\Stmt\Do_) { | |
| $this->setLineBranch( | |
| $node->cond->getStartLine(), | |
| $node->cond->getEndLine(), | |
| ++$this->nextBranch, | |
| ); | |
| 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; | |
| } | |
| $this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch); | |
| return; | |
| } | |
| if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) { | |
| return; | |
| } | |
| $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++; | |
| 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, | |
| ); | |
| } | |
| /** | |
| * @psalm-return LinesType | |
| */ | |
| 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; | |
| } | |
| } | |
| } | |
Xet Storage Details
- Size:
- 12.8 kB
- Xet hash:
- 68e031a50b7dce165fdb04ea9e8846aad9756c2d369c727cb2b190751b081262
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.