From 2bda8828ba33dfe3cf851b8ffb3201fd5b68bbf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Fri, 11 Nov 2022 19:48:22 +0100 Subject: [PATCH 1/7] Fix executable lines analysis Co-authored-by: Filippo Tessarotto --- .../ExecutableLinesFindingVisitor.php | 244 ++++++++----- .../_files/source_with_heavy_indentation.php | 133 ++++++++ .../source_with_multiline_constant_return.php | 321 ++++++++++++++++++ .../source_with_oneline_annotations.php | 4 + tests/tests/Data/RawCodeCoverageDataTest.php | 134 ++++++-- 5 files changed, 714 insertions(+), 122 deletions(-) diff --git a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php index f69363caf..9387d6de1 100644 --- a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php +++ b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php @@ -12,15 +12,14 @@ 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\Print_; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticPropertyFetch; use PhpParser\Node\Expr\Ternary; @@ -37,18 +36,17 @@ 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\Function_; 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\NodeAbstract; use PhpParser\NodeVisitorAbstract; /** @@ -67,19 +65,23 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract private $propertyLines = []; /** - * @psalm-var array + * @psalm-var array */ private $returns = []; public function enterNode(Node $node): void { + if (!$node instanceof NodeAbstract) { + return; + } + $this->savePropertyLines($node); if (!$this->isExecutable($node)) { return; } - foreach ($this->getLines($node) as $line) { + foreach ($this->getLines($node, false) as $line) { if (isset($this->propertyLines[$line])) { return; } @@ -88,170 +90,225 @@ public function enterNode(Node $node): void } } - /** - * @psalm-return array - */ - public function executableLines(): array + public function afterTraverse(array $nodes): void { $this->computeReturns(); sort($this->executableLines); + } + /** + * @psalm-return array + */ + public function executableLines(): array + { return $this->executableLines; } 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 Property) { + foreach (range($node->getStartLine(), $node->getEndLine()) as $index) { + $this->propertyLines[$index] = $index; + } } } private function computeReturns(): void { - foreach ($this->returns as $return) { - foreach (range($return->getStartLine(), $return->getEndLine()) as $loc) { - if (isset($this->executableLines[$loc])) { - continue 2; + foreach (array_reverse($this->returns) as $node) { + foreach (range($node->getStartLine(), $node->getEndLine()) as $index) { + if (isset($this->executableLines[$index])) { + continue; } } - $line = $return->getEndLine(); - - if ($return->expr !== null) { - $line = $return->expr->getStartLine(); + foreach ($this->getLines($node, true) as $line) { + $this->executableLines[$line] = $line; } - - $this->executableLines[$line] = $line; } } /** * @return int[] */ - private function getLines(Node $node): array + private function getLines(NodeAbstract $node, bool $fromReturns): array { - if ($node instanceof BinaryOp) { - if (($node->left instanceof Node\Scalar || - $node->left instanceof Node\Expr\ConstFetch) && - ($node->right instanceof Node\Scalar || - $node->right instanceof Node\Expr\ConstFetch)) { - return [$node->right->getStartLine()]; - } - - return []; - } - - if ($node instanceof Cast || - $node instanceof PropertyFetch || - $node instanceof NullsafePropertyFetch || - $node instanceof StaticPropertyFetch) { - return [$node->getEndLine()]; - } + if ($node instanceof Function_ || + $node instanceof ClassMethod || + $node instanceof Return_ || + $node instanceof Expression || + $node instanceof Assign || + $node instanceof Array_ + ) { + if (!$fromReturns) { + $this->returns[] = $node; + + if ($node instanceof ClassMethod && $node->name->name === '__construct') { + $existsAPromotedProperty = false; + + foreach ($node->getParams() as $param) { + if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) { + $existsAPromotedProperty = true; + + break; + } + } + + 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 ($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 []; + // ugly fix for non-fully AST based processing + // self::afterTraverse()/self::computeReturns() should be rewritten using self::leaveNode() + foreach (range($node->getStartLine(), $node->getEndLine()) as $index) { + if (isset($this->executableLines[$index]) && !($node instanceof Assign)) { + return []; + } } - if ([] === $node->items) { + // empty function + if ($node instanceof Function_) { return [$node->getEndLine()]; } - if ($node->items[0] instanceof ArrayItem) { - return [$node->items[0]->getStartLine()]; + // empty method + if ($node instanceof ClassMethod) { + if (null === $node->stmts) { // method without body (interface prototype) + return []; + } + + return [$node->getEndLine()]; } } - if ($node instanceof ClassMethod) { - if ($node->name->name !== '__construct') { - return []; + if ($node instanceof Return_) { + if ($node->expr === null) { + return [$node->getEndLine()]; } - $existsAPromotedProperty = false; + return $this->getLines($node->expr, $fromReturns); + } - foreach ($node->getParams() as $param) { - if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) { - $existsAPromotedProperty = true; + if ($node instanceof Expression) { + return $this->getLines($node->expr, $fromReturns); + } - break; - } - } + if ($node instanceof Assign) { + return [$this->getNodeStartLine($node->var)]; + } - 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 ($node instanceof BinaryOp) { + return $fromReturns ? $this->getLines($node->right, $fromReturns) : []; + } + + if ($node instanceof PropertyFetch || + $node instanceof NullsafePropertyFetch || + $node instanceof StaticPropertyFetch) { + return [$this->getNodeStartLine($node->name)]; + } - return []; + if ($node instanceof ArrayDimFetch && null !== $node->dim) { + return [$this->getNodeStartLine($node->dim)]; } if ($node instanceof MethodCall) { - return [$node->name->getStartLine()]; + return [$this->getNodeStartLine($node->name)]; } if ($node instanceof Ternary) { - $lines = [$node->cond->getStartLine()]; + $lines = [$this->getNodeStartLine($node->cond)]; if (null !== $node->if) { - $lines[] = $node->if->getStartLine(); + $lines[] = $this->getNodeStartLine($node->if); } - $lines[] = $node->else->getStartLine(); + $lines[] = $this->getNodeStartLine($node->else); return $lines; } if ($node instanceof Match_) { - return [$node->cond->getStartLine()]; + return [$this->getNodeStartLine($node->cond)]; } if ($node instanceof MatchArm) { - return [$node->body->getStartLine()]; + return [$this->getNodeStartLine($node->body)]; } - if ($node instanceof Expression && ( - $node->expr instanceof Cast || - $node->expr instanceof Match_ || - $node->expr instanceof MethodCall + // TODO this concept should be extended for every statement class like Foreach_, For_, ... + if ($node instanceof If_ || + $node instanceof ElseIf_ || + $node instanceof While_ || + $node instanceof Do_) { + return [$this->getNodeStartLine($node->cond)]; + } + + if ($node instanceof Case_) { + if (null === $node->cond) { // default case + return []; + } + + return [$this->getNodeStartLine($node->cond)]; + } + + if ($node instanceof Catch_) { + return [$this->getNodeStartLine($node->types[0])]; + } + + return [$this->getNodeStartLine($node)]; + } + + private function getNodeStartLine(NodeAbstract $node): int + { + if ($node instanceof Node\Expr\Cast || + $node instanceof Node\Expr\BooleanNot || + $node instanceof Node\Expr\UnaryMinus || + $node instanceof Node\Expr\UnaryPlus + ) { + return $this->getNodeStartLine($node->expr); + } + + if ($node instanceof BinaryOp) { + return $this->getNodeStartLine($node->right); + } + + if ($node instanceof Node\Scalar\String_ && ( + $node->getAttribute('kind') === Node\Scalar\String_::KIND_HEREDOC || + $node->getAttribute('kind') === Node\Scalar\String_::KIND_NOWDOC )) { - return []; + return $node->getStartLine() + 1; } - if ($node instanceof Return_) { - $this->returns[] = $node; + if ($node instanceof Array_) { + if ([] === $node->items || $node->items[0] === null) { + return $node->getEndLine(); + } + + return $this->getNodeStartLine($node->items[0]->value); + } - return []; + if ($node instanceof Assign) { + return $this->getNodeStartLine($node->expr); } - return [$node->getStartLine()]; + return $node->getStartLine(); // $node should be only a scalar here } private function isExecutable(Node $node): bool { 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 || @@ -262,22 +319,21 @@ private function isExecutable(Node $node): bool $node instanceof Else_ || $node instanceof Encapsed || $node instanceof Expression || - $node instanceof Finally_ || $node instanceof For_ || $node instanceof Foreach_ || + $node instanceof Function_ || $node instanceof Goto_ || $node instanceof If_ || $node instanceof Match_ || $node instanceof MatchArm || $node instanceof MethodCall || $node instanceof NullsafePropertyFetch || + $node instanceof Print_ || $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_; } diff --git a/tests/_files/source_with_heavy_indentation.php b/tests/_files/source_with_heavy_indentation.php index 64cea4a10..adf14512b 100644 --- a/tests/_files/source_with_heavy_indentation.php +++ b/tests/_files/source_with_heavy_indentation.php @@ -1,11 +1,27 @@ isOne(); + $xb = 1; + $xc = $xa; + + $va + = + $vb + = + [ + $xa, + $xb, + 1 + + + $xb + + 1, + ]; + + [ + $v2, + $v3 + ] + = + u( + $xa, + $xb, + 1 + + + $xc + + + 1 + ); + + return $v2 === $v3; + } + + public function noElse(): int + { + $res = 0; + if (mt_rand() === 0) { + return 1; + } elseif (mt_rand() === 0) { + return 2; + } else { + $res = 3; + } + + return $res; + } + + public function noDo(): int + { + $res = 0; + do { + if (mt_rand() !== 0) { + $res++; + } + } while ( + $res + < + 10 + ); + + return $res; + } + + public function noTryNoFinally(): int + { + $res = 0; + try { + if (mt_rand() === 0) { + throw new \Exception(); + } + } catch ( + \x\y + | + \x\z + $e + ) { + $res = 1; + } catch (\Error $e) { + $res = 1; + } finally { + $res += 10; + } + + return $res; + } + + public function switch(): int + { + switch ( + 'x' + . + mt_rand() + . 'x' + ) { + case + << 'fi_v', + 'omega', + ] + [ + 'f' + . 'i' + ] + ; + } + + public function emptyArray(): array + { + return + ( + [ + ] + ) + ; + } + + public function complexAssociativityNa2(): bool + { + return + ! + ! + ! + <<<'EOF' + foo + foo + EOF + ; + } + + public function unaryMinusNowdoc(): float + { + return + - + <<<'EOF' + 1. + 2 + EOF + ; + } + + public + function + emptyMethod + ( + ) + : + void + { + } + + public function emptyMethodWithComment(): void + { + // empty method with comment + } + + public function simpleConstArrayEmpty(): array + { + return + [ + // empty array with comment + ]; + } + + public function nestedConstArrayEmpty(): array + { + return + [ + [ + // empty subarray with comment + ] + ]; + } + + public function nestedConstArrayOne(): array + { + return + [ + [ + <<<'EOF' + 1 + EOF, + ] + ]; + } + + public function nestedConstArrayTwo(): array + { + return + [ + [ + <<<'EOF' + 1 + EOF, + 2, + ] + ]; + } + + public function nestedArrayWithExecutableInKey(): array + { + return + [ + [ + 1, + phpversion() + => + 2, + ] + ]; + } } diff --git a/tests/_files/source_with_oneline_annotations.php b/tests/_files/source_with_oneline_annotations.php index 7b1cb1cbd..7d3981e0a 100644 --- a/tests/_files/source_with_oneline_annotations.php +++ b/tests/_files/source_with_oneline_annotations.php @@ -34,3 +34,7 @@ function baz() print '*'; } + +function xyz() +{ +} diff --git a/tests/tests/Data/RawCodeCoverageDataTest.php b/tests/tests/Data/RawCodeCoverageDataTest.php index ae4e48803..841793a4e 100644 --- a/tests/tests/Data/RawCodeCoverageDataTest.php +++ b/tests/tests/Data/RawCodeCoverageDataTest.php @@ -272,7 +272,6 @@ public function testUseStatementsAreUncovered(): void [ 12, 14, - 15, 16, 18, ], @@ -300,7 +299,6 @@ public function testInterfacesAreUncovered(): void [ 7, 9, - 10, 11, 13, ], @@ -314,6 +312,7 @@ public function testInlineCommentsKeepTheLine(): void $this->assertEquals( [ + 13, 19, 22, 26, @@ -322,6 +321,7 @@ public function testInlineCommentsKeepTheLine(): void 32, 33, 35, + 40, ], array_keys(RawCodeCoverageData::fromUncoveredFile($file, new ParsingFileAnalyser(true, true))->lineCoverage()[$file]) ); @@ -333,44 +333,88 @@ public function testHeavyIndentationIsHandledCorrectly(): void $this->assertEquals( [ - 9, - 12, - 16, - 18, + 14, 19, - 24, + // line 22 is unstable - not in xdebug output if script is cached by opcache 25, - 28, - 31, - 36, + // line 28 is unstable - const coverage depends on autoload order - https://github.com/sebastianbergmann/php-code-coverage/issues/889 + 32, + 34, + 35, 40, - 46, - 48, - 54, - 60, + 41, + 44, + 47, + 56, + 62, 64, - 71, - 83, - 85, + 70, + 76, 87, - 89, - 91, - 93, 95, + 96, 97, 99, 101, - 116, - 120, - 123, - 125, // This shouldn't be marked as LoC, but it's high unlikely to happen IRL to have $var = []; on multiple lines + // line 108 is unstable - variable has no coverage if it holds const expr - https://github.com/sebastianbergmann/php-code-coverage/issues/953 + 113, + // array destruct element, should be present 114, + 117, + 127, 132, + 133, + 134, 135, - 139, - 143, + 136, + 137, + 138, + 141, + 146, + 148, 149, - 153, - 159, + 154, + 157, + 162, + // line 163 is try statement, not in xdebug output (only catch condition is covered) + 164, + 165, + 168, + 173, + 174, + 175, + // line 176 is finally statement, not in xdebug output (only catch condition is covered) + 177, + 180, + 188, + 193, + 195, + 197, + 198, + 199, + 200, + 202, + // line 203 is default case, not in xdebug output (only cases with condition are covered) + 204, + 207, + 216, + 218, + 220, + 222, + 224, + 226, + 228, + 230, + 232, + 234, + 256, + 261, + 265, + 268, + 272, + 276, + 282, + 286, + 292, ], array_keys(RawCodeCoverageData::fromUncoveredFile($file, new ParsingFileAnalyser(true, true))->lineCoverage()[$file]) ); @@ -460,6 +504,40 @@ public function testReturnStatementWithConstantExprOnlyReturnTheLineOfLast(): vo 226, 235, 244, + 252, + 261, + 269, + 278, + 293, + 304, + 314, + 321, + 323, + 324, + 325, + 327, + 340, + 351, + 370, + 377, + 390, + 402, + 414, + 425, + 437, + 442, + 444, + 459, + 469, + 481, + 492, + 506, + 511, + 518, + 527, + 537, + 549, + 562, ], array_keys(RawCodeCoverageData::fromUncoveredFile($file, new ParsingFileAnalyser(true, true))->lineCoverage()[$file]) ); From f59f6ac225a07ffc897f23536908537544808bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Fri, 11 Nov 2022 19:55:07 +0100 Subject: [PATCH 2/7] Fix else is not executable --- .../ExecutableLinesFindingVisitor.php | 2 -- tests/TestCase.php | 2 -- tests/_files/BankAccount-clover-line.xml | 7 +++--- tests/_files/BankAccount-clover-path.xml | 7 +++--- tests/_files/BankAccount-cobertura-line.xml | 8 +++---- tests/_files/BankAccount-cobertura-path.xml | 8 +++---- tests/_files/BankAccount-text-line.txt | 4 ++-- tests/_files/BankAccount-text-path.txt | 4 ++-- tests/_files/BankAccount-text-summary.txt | 2 +- .../BankAccountWithUncovered-text-line.txt | 4 ++-- .../BankAccountWithoutUncovered-text-line.txt | 4 ++-- tests/_files/NamespacedBankAccount-text.txt | 4 ++-- .../BankAccount.php.html | 22 +++++++++---------- .../CoverageForBankAccount/dashboard.html | 8 +++---- .../HTML/CoverageForBankAccount/index.html | 16 +++++++------- .../BankAccount.php.html | 20 ++++++++--------- .../BankAccount.php_branch.html | 18 +++++++-------- .../BankAccount.php_path.html | 18 +++++++-------- .../PathCoverageForBankAccount/index.html | 16 +++++++------- .../BankAccount.php.xml | 6 ++--- .../XML/CoverageForBankAccount/index.xml | 4 ++-- tests/tests/CodeCoverageTest.php | 1 - tests/tests/Data/RawCodeCoverageDataTest.php | 2 +- tests/tests/Node/BuilderTest.php | 12 +++++----- 24 files changed, 94 insertions(+), 105 deletions(-) diff --git a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php index 9387d6de1..6e1464e44 100644 --- a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php +++ b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php @@ -33,7 +33,6 @@ 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\For_; @@ -316,7 +315,6 @@ private function isExecutable(Node $node): bool $node instanceof Do_ || $node instanceof Echo_ || $node instanceof ElseIf_ || - $node instanceof Else_ || $node instanceof Encapsed || $node instanceof Expression || $node instanceof For_ || diff --git a/tests/TestCase.php b/tests/TestCase.php index d2d045c3a..1ddb311f3 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1353,7 +1353,6 @@ protected function getExpectedLineCoverageDataArrayForBankAccount(): array ], 13 => [], 14 => [], - 15 => [], 16 => [], 22 => [ 0 => 'BankAccountTest::testBalanceCannotBecomeNegative2', @@ -1384,7 +1383,6 @@ protected function getExpectedLineCoverageDataArrayForBankAccountInReverseOrder( ], 13 => [], 14 => [], - 15 => [], 16 => [], 22 => [ 0 => 'BankAccountTest::testBalanceCannotBecomeNegative2', diff --git a/tests/_files/BankAccount-clover-line.xml b/tests/_files/BankAccount-clover-line.xml index 02516b4a8..9a6fca706 100644 --- a/tests/_files/BankAccount-clover-line.xml +++ b/tests/_files/BankAccount-clover-line.xml @@ -3,14 +3,13 @@ - + - @@ -18,8 +17,8 @@ - + - + diff --git a/tests/_files/BankAccount-clover-path.xml b/tests/_files/BankAccount-clover-path.xml index a71babac5..b49f4c915 100644 --- a/tests/_files/BankAccount-clover-path.xml +++ b/tests/_files/BankAccount-clover-path.xml @@ -3,14 +3,13 @@ - + - @@ -18,8 +17,8 @@ - + - + diff --git a/tests/_files/BankAccount-cobertura-line.xml b/tests/_files/BankAccount-cobertura-line.xml index 3671bc7aa..75401a6cb 100644 --- a/tests/_files/BankAccount-cobertura-line.xml +++ b/tests/_files/BankAccount-cobertura-line.xml @@ -1,13 +1,13 @@ - + %s - + - + @@ -18,7 +18,6 @@ - @@ -39,7 +38,6 @@ - diff --git a/tests/_files/BankAccount-cobertura-path.xml b/tests/_files/BankAccount-cobertura-path.xml index 12fd5d537..9ce9efe6e 100644 --- a/tests/_files/BankAccount-cobertura-path.xml +++ b/tests/_files/BankAccount-cobertura-path.xml @@ -1,13 +1,13 @@ - + %s - + - + @@ -18,7 +18,6 @@ - @@ -39,7 +38,6 @@ - diff --git a/tests/_files/BankAccount-text-line.txt b/tests/_files/BankAccount-text-line.txt index 133c73797..4f188c76c 100644 --- a/tests/_files/BankAccount-text-line.txt +++ b/tests/_files/BankAccount-text-line.txt @@ -6,7 +6,7 @@ Code Coverage Report: Summary: Classes: 0.00% (0/1) Methods: 75.00% (3/4) - Lines: 55.56% (5/9) + Lines: 62.50% (5/8) BankAccount - Methods: 75.00% ( 3/ 4) Lines: 55.56% ( 5/ 9) + Methods: 75.00% ( 3/ 4) Lines: 62.50% ( 5/ 8) diff --git a/tests/_files/BankAccount-text-path.txt b/tests/_files/BankAccount-text-path.txt index 653f9ffed..488e34ff5 100644 --- a/tests/_files/BankAccount-text-path.txt +++ b/tests/_files/BankAccount-text-path.txt @@ -8,7 +8,7 @@ Code Coverage Report: Methods: 75.00% (3/4) Paths: 60.00% (3/5) Branches: 42.86% (3/7) - Lines: 55.56% (5/9) + Lines: 62.50% (5/8) BankAccount - Methods: 75.00% ( 3/ 4) Paths: 60.00% ( 3/ 5) Branches: 42.86% ( 3/ 7) Lines: 55.56% ( 5/ 9) + Methods: 75.00% ( 3/ 4) Paths: 60.00% ( 3/ 5) Branches: 42.86% ( 3/ 7) Lines: 62.50% ( 5/ 8) diff --git a/tests/_files/BankAccount-text-summary.txt b/tests/_files/BankAccount-text-summary.txt index 96390c4cd..952abd17b 100644 --- a/tests/_files/BankAccount-text-summary.txt +++ b/tests/_files/BankAccount-text-summary.txt @@ -3,5 +3,5 @@ Code Coverage Report Summary: Classes: 0.00% (0/1) Methods: 75.00% (3/4) - Lines: 55.56% (5/9) + Lines: 62.50% (5/8) diff --git a/tests/_files/BankAccountWithUncovered-text-line.txt b/tests/_files/BankAccountWithUncovered-text-line.txt index 4193b5ec7..85693d8af 100644 --- a/tests/_files/BankAccountWithUncovered-text-line.txt +++ b/tests/_files/BankAccountWithUncovered-text-line.txt @@ -6,7 +6,7 @@ Code Coverage Report: Summary: Classes: 0.00% (0/2) Methods: 37.50% (3/8) - Lines: 27.78% (5/18) + Lines: 31.25% (5/16) BankAccount - Methods: 75.00% ( 3/ 4) Lines: 55.56% ( 5/ 9) + Methods: 75.00% ( 3/ 4) Lines: 62.50% ( 5/ 8) diff --git a/tests/_files/BankAccountWithoutUncovered-text-line.txt b/tests/_files/BankAccountWithoutUncovered-text-line.txt index 133c73797..4f188c76c 100644 --- a/tests/_files/BankAccountWithoutUncovered-text-line.txt +++ b/tests/_files/BankAccountWithoutUncovered-text-line.txt @@ -6,7 +6,7 @@ Code Coverage Report: Summary: Classes: 0.00% (0/1) Methods: 75.00% (3/4) - Lines: 55.56% (5/9) + Lines: 62.50% (5/8) BankAccount - Methods: 75.00% ( 3/ 4) Lines: 55.56% ( 5/ 9) + Methods: 75.00% ( 3/ 4) Lines: 62.50% ( 5/ 8) diff --git a/tests/_files/NamespacedBankAccount-text.txt b/tests/_files/NamespacedBankAccount-text.txt index 4cd9eb18f..7cede93cb 100644 --- a/tests/_files/NamespacedBankAccount-text.txt +++ b/tests/_files/NamespacedBankAccount-text.txt @@ -6,9 +6,9 @@ Code Coverage Report: Summary: Classes: 0.00% (0/1) Methods: 75.00% (3/4) - Lines: 55.56% (5/9) + Lines: 62.50% (5/8) SomeNamespace\BankAccount Methods: ( 0/ 0) Lines: ( 0/ 0) SomeNamespace\BankAccountTrait - Methods: 75.00% ( 3/ 4) Lines: 55.56% ( 5/ 9) + Methods: 75.00% ( 3/ 4) Lines: 62.50% ( 5/ 8) diff --git a/tests/_files/Report/HTML/CoverageForBankAccount/BankAccount.php.html b/tests/_files/Report/HTML/CoverageForBankAccount/BankAccount.php.html index ee67f746d..fcbd196c3 100644 --- a/tests/_files/Report/HTML/CoverageForBankAccount/BankAccount.php.html +++ b/tests/_files/Report/HTML/CoverageForBankAccount/BankAccount.php.html @@ -44,13 +44,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
75.00% covered (warning) @@ -73,13 +73,13 @@ BankAccount
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
75.00% covered (warning) @@ -88,7 +88,7 @@
75.00%
3 / 4
- 7.19 + 6.32
0.00% covered (danger) @@ -130,7 +130,7 @@
0.00%
-
0 / 4
+
0 / 3
0.00% covered (danger) @@ -207,7 +207,7 @@ 12    { 13        if ($balance >= 0) { 14            $this->balance = $balance; - 15        } else { + 15        } else { 16            throw new RuntimeException; 17        } 18    } diff --git a/tests/_files/Report/HTML/CoverageForBankAccount/dashboard.html b/tests/_files/Report/HTML/CoverageForBankAccount/dashboard.html index fc20fb36e..13016f8cd 100644 --- a/tests/_files/Report/HTML/CoverageForBankAccount/dashboard.html +++ b/tests/_files/Report/HTML/CoverageForBankAccount/dashboard.html @@ -57,7 +57,7 @@

Insufficient Coverage

- BankAccount55% + BankAccount62% @@ -74,7 +74,7 @@

Project Risks

- BankAccount7 + BankAccount6 @@ -158,7 +158,7 @@

Project Risks

.yAxis.tickFormat(d3.format('d')); d3.select('#classCoverageDistribution svg') - .datum(getCoverageDistributionData([0,0,0,0,0,0,1,0,0,0,0,0], "Class Coverage")) + .datum(getCoverageDistributionData([0,0,0,0,0,0,0,1,0,0,0,0], "Class Coverage")) .transition().duration(500).call(chart); nv.utils.windowResize(chart.update); @@ -226,7 +226,7 @@

Project Risks

chart.yAxis.axisLabel('Cyclomatic Complexity'); d3.select('#classComplexity svg') - .datum(getComplexityData([[55.555555555556,5,"BankAccount<\/a>"]], 'Class Complexity')) + .datum(getComplexityData([[62.5,5,"BankAccount<\/a>"]], 'Class Complexity')) .transition() .duration(500) .call(chart); diff --git a/tests/_files/Report/HTML/CoverageForBankAccount/index.html b/tests/_files/Report/HTML/CoverageForBankAccount/index.html index 89ab27d54..d21ece67a 100644 --- a/tests/_files/Report/HTML/CoverageForBankAccount/index.html +++ b/tests/_files/Report/HTML/CoverageForBankAccount/index.html @@ -44,13 +44,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
75.00% covered (warning) @@ -72,13 +72,13 @@ BankAccount.php
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
75.00% covered (warning) diff --git a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php.html b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php.html index 15aec8765..5680ed189 100644 --- a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php.html +++ b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php.html @@ -46,13 +46,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -91,13 +91,13 @@ BankAccount
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -180,7 +180,7 @@
0.00%
-
0 / 4
+
0 / 3
0.00% covered (danger) @@ -305,7 +305,7 @@ 12    { 13        if ($balance >= 0) { 14            $this->balance = $balance; - 15        } else { + 15        } else { 16            throw new RuntimeException; 17        } 18    } diff --git a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_branch.html b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_branch.html index 6a89c22ec..fe4a8a066 100644 --- a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_branch.html +++ b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_branch.html @@ -46,13 +46,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -91,13 +91,13 @@ BankAccount
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -180,7 +180,7 @@
0.00%
-
0 / 4
+
0 / 3
0.00% covered (danger) diff --git a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_path.html b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_path.html index aa8f776b2..de13b9a4f 100644 --- a/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_path.html +++ b/tests/_files/Report/HTML/PathCoverageForBankAccount/BankAccount.php_path.html @@ -46,13 +46,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -91,13 +91,13 @@ BankAccount
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -180,7 +180,7 @@
0.00%
-
0 / 4
+
0 / 3
0.00% covered (danger) diff --git a/tests/_files/Report/HTML/PathCoverageForBankAccount/index.html b/tests/_files/Report/HTML/PathCoverageForBankAccount/index.html index c31d0b7a7..b3616eeec 100644 --- a/tests/_files/Report/HTML/PathCoverageForBankAccount/index.html +++ b/tests/_files/Report/HTML/PathCoverageForBankAccount/index.html @@ -46,13 +46,13 @@ Total
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) @@ -90,13 +90,13 @@ BankAccount.php [line] [branch] [path]
-
- 55.56% covered (warning) +
+ 62.50% covered (warning)
-
55.56%
-
5 / 9
+
62.50%
+
5 / 8
42.86% covered (danger) diff --git a/tests/_files/Report/XML/CoverageForBankAccount/BankAccount.php.xml b/tests/_files/Report/XML/CoverageForBankAccount/BankAccount.php.xml index c9209d0e6..b49cdf8ed 100644 --- a/tests/_files/Report/XML/CoverageForBankAccount/BankAccount.php.xml +++ b/tests/_files/Report/XML/CoverageForBankAccount/BankAccount.php.xml @@ -2,16 +2,16 @@ - + - + - + diff --git a/tests/_files/Report/XML/CoverageForBankAccount/index.xml b/tests/_files/Report/XML/CoverageForBankAccount/index.xml index ee3df1efc..a18d5d871 100644 --- a/tests/_files/Report/XML/CoverageForBankAccount/index.xml +++ b/tests/_files/Report/XML/CoverageForBankAccount/index.xml @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + diff --git a/tests/tests/CodeCoverageTest.php b/tests/tests/CodeCoverageTest.php index 8de789819..d17aec88b 100644 --- a/tests/tests/CodeCoverageTest.php +++ b/tests/tests/CodeCoverageTest.php @@ -108,7 +108,6 @@ public function testExcludeNonExecutableLines(): void 8 => [], 13 => [], 14 => [], - 15 => [], 16 => [], 22 => [], 24 => [], diff --git a/tests/tests/Data/RawCodeCoverageDataTest.php b/tests/tests/Data/RawCodeCoverageDataTest.php index 841793a4e..559187f9a 100644 --- a/tests/tests/Data/RawCodeCoverageDataTest.php +++ b/tests/tests/Data/RawCodeCoverageDataTest.php @@ -366,7 +366,7 @@ public function testHeavyIndentationIsHandledCorrectly(): void 134, 135, 136, - 137, + // line 137 is else statement, not in xdebug output (only if/elseif conditions are covered) 138, 141, 146, diff --git a/tests/tests/Node/BuilderTest.php b/tests/tests/Node/BuilderTest.php index dba2fd28e..681d189f3 100644 --- a/tests/tests/Node/BuilderTest.php +++ b/tests/tests/Node/BuilderTest.php @@ -32,7 +32,7 @@ public function testSomething(): void $expectedPath = rtrim(TEST_FILES_PATH, DIRECTORY_SEPARATOR); $this->assertEquals($expectedPath, $root->name()); $this->assertEquals($expectedPath, $root->pathAsString()); - $this->assertEquals(9, $root->numberOfExecutableLines()); + $this->assertEquals(8, $root->numberOfExecutableLines()); $this->assertEquals(5, $root->numberOfExecutedLines()); $this->assertEquals(1, $root->numberOfClasses()); $this->assertEquals(0, $root->numberOfTestedClasses()); @@ -40,7 +40,7 @@ public function testSomething(): void $this->assertEquals(3, $root->numberOfTestedMethods()); $this->assertEquals('0.00%', $root->percentageOfTestedClasses()->asString()); $this->assertEquals('75.00%', $root->percentageOfTestedMethods()->asString()); - $this->assertEquals('55.56%', $root->percentageOfExecutedLines()->asString()); + $this->assertEquals('62.50%', $root->percentageOfExecutedLines()->asString()); $this->assertEquals(0, $root->numberOfFunctions()); $this->assertEquals(0, $root->numberOfTestedFunctions()); $this->assertNull($root->parent()); @@ -73,7 +73,7 @@ public function testSomething(): void 'signature' => 'setBalance($balance)', 'startLine' => 11, 'endLine' => 18, - 'executableLines' => 4, + 'executableLines' => 3, 'executedLines' => 0, 'executableBranches' => 0, 'executedBranches' => 0, @@ -122,15 +122,15 @@ public function testSomething(): void ], ], 'startLine' => 2, - 'executableLines' => 9, + 'executableLines' => 8, 'executedLines' => 5, 'executableBranches' => 0, 'executedBranches' => 0, 'executablePaths' => 0, 'executedPaths' => 0, 'ccn' => 5, - 'coverage' => 55.55555555555556, - 'crap' => '7.19', + 'coverage' => 62.5, + 'crap' => '6.32', 'link' => 'BankAccount.php.html#2', 'className' => 'BankAccount', 'namespace' => '', From b634378fef9d80637b31a50c073e3064ce10c19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Mon, 14 Nov 2022 10:18:40 +0100 Subject: [PATCH 3/7] Test binary concat the same as binary plus --- .../_files/source_with_heavy_indentation.php | 39 +++++++- tests/tests/Data/RawCodeCoverageDataTest.php | 88 +++++++++++-------- 2 files changed, 87 insertions(+), 40 deletions(-) diff --git a/tests/_files/source_with_heavy_indentation.php b/tests/_files/source_with_heavy_indentation.php index adf14512b..15f50753e 100644 --- a/tests/_files/source_with_heavy_indentation.php +++ b/tests/_files/source_with_heavy_indentation.php @@ -90,7 +90,7 @@ public function isTwo(): bool ], true); } - public function variable(): bool + public function variableBinaryPlus(): bool { $xa = $this->isOne(); $xb = 1; @@ -127,6 +127,43 @@ public function variable(): bool return $v2 === $v3; } + public function variableBinaryConcat(): bool + { + $xa = $this->isOne(); + $xb = 1; + $xc = $xa; + + $va + = + $vb + = + [ + $xa, + $xb, + 1 + . + $xb + . 1, + ]; + + [ + $v2, + $v3 + ] + = + u( + $xa, + $xb, + 1 + . + $xc + . + 1 + ); + + return $v2 === $v3; + } + public function noElse(): int { $res = 0; diff --git a/tests/tests/Data/RawCodeCoverageDataTest.php b/tests/tests/Data/RawCodeCoverageDataTest.php index 559187f9a..43aab64a1 100644 --- a/tests/tests/Data/RawCodeCoverageDataTest.php +++ b/tests/tests/Data/RawCodeCoverageDataTest.php @@ -358,63 +358,73 @@ public function testHeavyIndentationIsHandledCorrectly(): void 101, // line 108 is unstable - variable has no coverage if it holds const expr - https://github.com/sebastianbergmann/php-code-coverage/issues/953 113, - // array destruct element, should be present 114, + // array destruct element, should be present 114 117, 127, 132, 133, 134, - 135, 136, - // line 137 is else statement, not in xdebug output (only if/elseif conditions are covered) 138, - 141, - 146, - 148, - 149, + // line 145 is unstable - same reason as line 108 + 150, + // array destruct element, should be present 151 - same reason as line 114 154, - 157, - 162, - // line 163 is try statement, not in xdebug output (only catch condition is covered) 164, - 165, - 168, + 169, + 170, + 171, + 172, 173, - 174, + // line 174 is else statement, not in xdebug output (only if/elseif conditions are covered) 175, - // line 176 is finally statement, not in xdebug output (only catch condition is covered) - 177, - 180, - 188, - 193, - 195, - 197, - 198, + 178, + 183, + 185, + 186, + 191, + 194, 199, - 200, + // line 200 is try statement, not in xdebug output (only catch condition is covered) + 201, 202, - // line 203 is default case, not in xdebug output (only cases with condition are covered) - 204, - 207, - 216, - 218, - 220, - 222, - 224, - 226, - 228, + 205, + 210, + 211, + 212, + // line 213 is finally statement, not in xdebug output (only catch condition is covered) + 214, + 217, + 225, 230, 232, 234, - 256, + 235, + 236, + 237, + 239, + // line 240 is default case, not in xdebug output (only cases with condition are covered) + 241, + 244, + 253, + 255, + 257, + 259, 261, + 263, 265, - 268, - 272, - 276, - 282, - 286, - 292, + 267, + 269, + 271, + 293, + 298, + 302, + 305, + 309, + 313, + 319, + 323, + 329, ], array_keys(RawCodeCoverageData::fromUncoveredFile($file, new ParsingFileAnalyser(true, true))->lineCoverage()[$file]) ); From bb11fffd6d9128cc20ad2ed2f3c11602eb74e828 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Wed, 16 Nov 2022 05:16:05 +0100 Subject: [PATCH 4/7] Assert that we have an Identifier here --- src/StaticAnalysis/CodeUnitFindingVisitor.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/StaticAnalysis/CodeUnitFindingVisitor.php b/src/StaticAnalysis/CodeUnitFindingVisitor.php index 8d357b202..e3e2fb05d 100644 --- a/src/StaticAnalysis/CodeUnitFindingVisitor.php +++ b/src/StaticAnalysis/CodeUnitFindingVisitor.php @@ -314,6 +314,8 @@ private function unionOrIntersectionAsString(ComplexType $type): string if ($_type instanceof Name) { $types[] = $_type->toCodeString(); } else { + assert($_type instanceof Identifier); + $types[] = $_type->toString(); } } From 2bdb857b4d2a21dcadf425019dda5df5b9654445 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Wed, 16 Nov 2022 05:18:03 +0100 Subject: [PATCH 5/7] Update ChangeLog --- ChangeLog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 24764a3e5..c972cf032 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,10 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt ## [9.2.19] - 2022-MM-DD +### Fixed + +* [#949](https://github.com/sebastianbergmann/php-code-coverage/pull/949): Various issues related to identifying executable lines + ### Changed * Tweaked CSS for HTML report From bc1ff2477b357f809d1af657657ab6da70fcc397 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Wed, 16 Nov 2022 05:22:12 +0100 Subject: [PATCH 6/7] Update PHP-CS-Fixer configuration --- .php-cs-fixer.dist.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 3e2ad19c0..d5f7b271e 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -119,9 +119,16 @@ 'multiline_whitespace_before_semicolons' => true, 'native_constant_invocation' => false, 'native_function_casing' => false, - 'native_function_invocation' => false, + 'native_function_invocation' => [ + 'include' => [ + '@internal', + ], + ], 'native_function_type_declaration_casing' => true, - 'new_with_braces' => false, + 'new_with_braces' => [ + 'named_class' => false, + 'anonymous_class' => false, + ], 'no_alias_functions' => true, 'no_alias_language_construct_call' => true, 'no_alternative_syntax' => true, @@ -158,6 +165,7 @@ 'no_unneeded_control_parentheses' => true, 'no_unneeded_curly_braces' => true, 'no_unneeded_final_method' => true, + 'no_unneeded_import_alias' => true, 'no_unreachable_default_argument_value' => true, 'no_unset_cast' => true, 'no_unset_on_property' => true, From 2dfaeeb12a6fdff91557d2817828f82a09e53c73 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Wed, 16 Nov 2022 05:22:16 +0100 Subject: [PATCH 7/7] Fix CS/WS issues --- src/RawCodeCoverageData.php | 4 ++++ src/Report/Cobertura.php | 3 +++ src/Report/Html/Renderer/File.php | 5 +++++ src/Report/Xml/Coverage.php | 2 +- src/Report/Xml/Report.php | 2 +- src/Report/Xml/Source.php | 2 +- src/StaticAnalysis/CachingFileAnalyser.php | 1 + src/StaticAnalysis/CodeUnitFindingVisitor.php | 1 + src/StaticAnalysis/ExecutableLinesFindingVisitor.php | 3 +++ src/StaticAnalysis/ParsingFileAnalyser.php | 2 ++ tests/tests/CodeCoverageTest.php | 1 + tests/tests/Data/ProcessedCodeCoverageDataTest.php | 2 +- tests/tests/StaticAnalysis/CodeUnitFindingVisitorTest.php | 1 + 13 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/RawCodeCoverageData.php b/src/RawCodeCoverageData.php index 422742e28..c8d3eb75c 100644 --- a/src/RawCodeCoverageData.php +++ b/src/RawCodeCoverageData.php @@ -15,8 +15,12 @@ use function array_intersect; use function array_intersect_key; use function count; +use function explode; +use function file_get_contents; use function in_array; +use function is_file; use function range; +use function trim; use SebastianBergmann\CodeCoverage\Driver\Driver; use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; diff --git a/src/Report/Cobertura.php b/src/Report/Cobertura.php index f9a7ed3eb..0d1dde760 100644 --- a/src/Report/Cobertura.php +++ b/src/Report/Cobertura.php @@ -9,10 +9,13 @@ */ namespace SebastianBergmann\CodeCoverage\Report; +use function basename; use function count; use function dirname; use function file_put_contents; +use function preg_match; use function range; +use function str_replace; use function time; use DOMImplementation; use SebastianBergmann\CodeCoverage\CodeCoverage; diff --git a/src/Report/Html/Renderer/File.php b/src/Report/Html/Renderer/File.php index d47267e33..101a9adae 100644 --- a/src/Report/Html/Renderer/File.php +++ b/src/Report/Html/Renderer/File.php @@ -80,6 +80,8 @@ use const T_YIELD; use const T_YIELD_FROM; use function array_key_exists; +use function array_keys; +use function array_merge; use function array_pop; use function array_unique; use function constant; @@ -89,6 +91,9 @@ use function file_get_contents; use function htmlspecialchars; use function is_string; +use function ksort; +use function range; +use function sort; use function sprintf; use function str_replace; use function substr; diff --git a/src/Report/Xml/Coverage.php b/src/Report/Xml/Coverage.php index 215f9b932..b556d8205 100644 --- a/src/Report/Xml/Coverage.php +++ b/src/Report/Xml/Coverage.php @@ -37,7 +37,7 @@ public function __construct(DOMElement $context, string $line) { $this->contextNode = $context; - $this->writer = new XMLWriter(); + $this->writer = new XMLWriter; $this->writer->openMemory(); $this->writer->startElementNS(null, $context->nodeName, 'https://schema.phpunit.de/coverage/1.0'); $this->writer->writeAttribute('nr', $line); diff --git a/src/Report/Xml/Report.php b/src/Report/Xml/Report.php index b53b08c00..7f2badaeb 100644 --- a/src/Report/Xml/Report.php +++ b/src/Report/Xml/Report.php @@ -20,7 +20,7 @@ final class Report extends File { public function __construct(string $name) { - $dom = new DOMDocument(); + $dom = new DOMDocument; $dom->loadXML(''); $contextNode = $dom->getElementsByTagNameNS( diff --git a/src/Report/Xml/Source.php b/src/Report/Xml/Source.php index 8fd20f58f..2b67ce1da 100644 --- a/src/Report/Xml/Source.php +++ b/src/Report/Xml/Source.php @@ -31,7 +31,7 @@ public function setSourceCode(string $source): void { $context = $this->context; - $tokens = (new Tokenizer())->parse($source); + $tokens = (new Tokenizer)->parse($source); $srcDom = (new XMLSerializer(new NamespaceUri($context->namespaceURI)))->toDom($tokens); $context->parentNode->replaceChild( diff --git a/src/StaticAnalysis/CachingFileAnalyser.php b/src/StaticAnalysis/CachingFileAnalyser.php index ceb39d51a..f53da078a 100644 --- a/src/StaticAnalysis/CachingFileAnalyser.php +++ b/src/StaticAnalysis/CachingFileAnalyser.php @@ -15,6 +15,7 @@ use function is_file; use function md5; use function serialize; +use function unserialize; use SebastianBergmann\CodeCoverage\Util\Filesystem; use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; diff --git a/src/StaticAnalysis/CodeUnitFindingVisitor.php b/src/StaticAnalysis/CodeUnitFindingVisitor.php index e3e2fb05d..8a2003fa8 100644 --- a/src/StaticAnalysis/CodeUnitFindingVisitor.php +++ b/src/StaticAnalysis/CodeUnitFindingVisitor.php @@ -9,6 +9,7 @@ */ namespace SebastianBergmann\CodeCoverage\StaticAnalysis; +use function assert; use function implode; use function rtrim; use function trim; diff --git a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php index 6e1464e44..1ef8e59c5 100644 --- a/src/StaticAnalysis/ExecutableLinesFindingVisitor.php +++ b/src/StaticAnalysis/ExecutableLinesFindingVisitor.php @@ -9,6 +9,9 @@ */ namespace SebastianBergmann\CodeCoverage\StaticAnalysis; +use function array_reverse; +use function range; +use function sort; use PhpParser\Node; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayDimFetch; diff --git a/src/StaticAnalysis/ParsingFileAnalyser.php b/src/StaticAnalysis/ParsingFileAnalyser.php index 8edf973e2..8792cf3d9 100644 --- a/src/StaticAnalysis/ParsingFileAnalyser.php +++ b/src/StaticAnalysis/ParsingFileAnalyser.php @@ -9,11 +9,13 @@ */ 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 sort; use function sprintf; use function substr_count; use function token_get_all; diff --git a/tests/tests/CodeCoverageTest.php b/tests/tests/CodeCoverageTest.php index d17aec88b..80c8c8f92 100644 --- a/tests/tests/CodeCoverageTest.php +++ b/tests/tests/CodeCoverageTest.php @@ -9,6 +9,7 @@ */ namespace SebastianBergmann\CodeCoverage; +use function array_fill; use SebastianBergmann\CodeCoverage\Driver\Driver; use SebastianBergmann\CodeCoverage\Driver\Selector; use SebastianBergmann\Environment\Runtime; diff --git a/tests/tests/Data/ProcessedCodeCoverageDataTest.php b/tests/tests/Data/ProcessedCodeCoverageDataTest.php index 13758f18a..206634041 100644 --- a/tests/tests/Data/ProcessedCodeCoverageDataTest.php +++ b/tests/tests/Data/ProcessedCodeCoverageDataTest.php @@ -40,7 +40,7 @@ public function testMergeWithPathCoverage(): void public function testMergeWithPathCoverageIntoEmpty(): void { - $coverage = new ProcessedCodeCoverageData(); + $coverage = new ProcessedCodeCoverageData; $coverage->merge($this->getPathCoverageForBankAccount()->getData()); diff --git a/tests/tests/StaticAnalysis/CodeUnitFindingVisitorTest.php b/tests/tests/StaticAnalysis/CodeUnitFindingVisitorTest.php index ffe06c8df..1c9d3aa2b 100644 --- a/tests/tests/StaticAnalysis/CodeUnitFindingVisitorTest.php +++ b/tests/tests/StaticAnalysis/CodeUnitFindingVisitorTest.php @@ -9,6 +9,7 @@ */ namespace SebastianBergmann\CodeCoverage\StaticAnalysis; +use function assert; use function file_get_contents; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\NameResolver;