20250204
This commit is contained in:
74
vendor/phpunit/php-code-coverage/ChangeLog-11.0.md
vendored
Normal file
74
vendor/phpunit/php-code-coverage/ChangeLog-11.0.md
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# ChangeLog
|
||||
|
||||
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
|
||||
|
||||
## [11.0.8] - 2024-12-11
|
||||
|
||||
### Changed
|
||||
|
||||
* [#1054](https://github.com/sebastianbergmann/php-code-coverage/pull/1054): Use click event for toggling "tests covering this line" popover in HTML report
|
||||
|
||||
## [11.0.7] - 2024-10-09
|
||||
|
||||
### Changed
|
||||
|
||||
* [#1037](https://github.com/sebastianbergmann/php-code-coverage/pull/1037): Upgrade Bootstrap to version 5.3.3 for HTML report
|
||||
* [#1046](https://github.com/sebastianbergmann/php-code-coverage/pull/1046): CSS fixes for HTML report
|
||||
|
||||
### Deprecated
|
||||
|
||||
* The `SebastianBergmann\CodeCoverage\Filter::includeUncoveredFiles()`, `SebastianBergmann\CodeCoverage\Filter::excludeUncoveredFiles()`, and `SebastianBergmann\CodeCoverage\Filter::excludeFile()` methods have been deprecated
|
||||
|
||||
## [11.0.6] - 2024-08-22
|
||||
|
||||
### Changed
|
||||
|
||||
* Updated dependencies (so that users that install using Composer's `--prefer-lowest` CLI option also get recent versions)
|
||||
|
||||
## [11.0.5] - 2024-07-03
|
||||
|
||||
### Changed
|
||||
|
||||
* This project now uses PHPStan instead of Psalm for static analysis
|
||||
|
||||
## [11.0.4] - 2024-06-29
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#967](https://github.com/sebastianbergmann/php-code-coverage/issues/967): Identification of executable lines for `match` expressions does not work correctly
|
||||
|
||||
## [11.0.3] - 2024-03-12
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#1033](https://github.com/sebastianbergmann/php-code-coverage/issues/1033): `@codeCoverageIgnore` annotation does not work on `enum`
|
||||
|
||||
## [11.0.2] - 2024-03-09
|
||||
|
||||
### Changed
|
||||
|
||||
* [#1032](https://github.com/sebastianbergmann/php-code-coverage/pull/1032): Pad lines in code coverage report only when colors are shown
|
||||
|
||||
## [11.0.1] - 2024-03-02
|
||||
|
||||
### Changed
|
||||
|
||||
* Do not use implicitly nullable parameters
|
||||
|
||||
## [11.0.0] - 2024-02-02
|
||||
|
||||
### Removed
|
||||
|
||||
* The `SebastianBergmann\CodeCoverage\Filter::includeDirectory()`, `SebastianBergmann\CodeCoverage\Filter::excludeDirectory()`, and `SebastianBergmann\CodeCoverage\Filter::excludeFile()` methods have been removed
|
||||
* This component now requires PHP-Parser 5
|
||||
* This component is no longer supported on PHP 8.1
|
||||
|
||||
[11.0.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.7...11.0.8
|
||||
[11.0.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.6...11.0.7
|
||||
[11.0.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.5...11.0.6
|
||||
[11.0.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.4...11.0.5
|
||||
[11.0.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.3...11.0.4
|
||||
[11.0.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.2...11.0.3
|
||||
[11.0.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.1...11.0.2
|
||||
[11.0.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0.0...11.0.1
|
||||
[11.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/10.1...11.0.0
|
@@ -1,19 +0,0 @@
|
||||
# ChangeLog
|
||||
|
||||
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
|
||||
|
||||
## [12.0.0] - 2025-02-07
|
||||
|
||||
### Changed
|
||||
|
||||
* `CodeCoverage::stop()` and `CodeCoverage::append()` now expect arguments of type `TargetCollection` instead of `array` to configure code coverage targets
|
||||
|
||||
### Removed
|
||||
|
||||
* Methods `CodeCoverage::includeUncoveredFiles()` and `CodeCoverage::excludeUncoveredFiles()`
|
||||
* Method `CodeCoverage::detectsDeadCode()`
|
||||
* Optional argument `$linesToBeUsed` of `CodeCoverage::stop()` and `CodeCoverage::append()` methods
|
||||
* This component is no longer supported on PHP 8.2
|
||||
* This component no longer supports Xdebug versions before Xdebug 3.1
|
||||
|
||||
[12.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/11.0...main
|
2
vendor/phpunit/php-code-coverage/LICENSE
vendored
2
vendor/phpunit/php-code-coverage/LICENSE
vendored
@@ -1,6 +1,6 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2009-2025, Sebastian Bergmann
|
||||
Copyright (c) 2009-2024, Sebastian Bergmann
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
24
vendor/phpunit/php-code-coverage/composer.json
vendored
24
vendor/phpunit/php-code-coverage/composer.json
vendored
@@ -22,29 +22,29 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.3.0"
|
||||
"php": "8.2.0"
|
||||
},
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"php": ">=8.2",
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^5.4.0",
|
||||
"phpunit/php-file-iterator": "^6.0-dev",
|
||||
"phpunit/php-text-template": "^5.0-dev",
|
||||
"sebastian/complexity": "^5.0-dev",
|
||||
"sebastian/environment": "^8.0-dev",
|
||||
"sebastian/lines-of-code": "^4.0-dev",
|
||||
"sebastian/version": "^6.0-dev",
|
||||
"nikic/php-parser": "^5.3.1",
|
||||
"phpunit/php-file-iterator": "^5.1.0",
|
||||
"phpunit/php-text-template": "^4.0.1",
|
||||
"sebastian/code-unit-reverse-lookup": "^4.0.1",
|
||||
"sebastian/complexity": "^4.0.1",
|
||||
"sebastian/environment": "^7.2.0",
|
||||
"sebastian/lines-of-code": "^3.0.1",
|
||||
"sebastian/version": "^5.0.2",
|
||||
"theseer/tokenizer": "^1.2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^12.0-dev"
|
||||
"phpunit/phpunit": "^11.5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
@@ -62,7 +62,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "12.0.x-dev"
|
||||
"dev-main": "11.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,9 +14,11 @@ use function array_diff_key;
|
||||
use function array_flip;
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function array_merge_recursive;
|
||||
use function array_unique;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function is_array;
|
||||
use function is_file;
|
||||
use function sort;
|
||||
use ReflectionClass;
|
||||
@@ -28,33 +30,37 @@ use SebastianBergmann\CodeCoverage\Node\Directory;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\CachingFileAnalyser;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingFileAnalyser;
|
||||
use SebastianBergmann\CodeCoverage\Test\Target\MapBuilder;
|
||||
use SebastianBergmann\CodeCoverage\Test\Target\Mapper;
|
||||
use SebastianBergmann\CodeCoverage\Test\Target\TargetCollection;
|
||||
use SebastianBergmann\CodeCoverage\Test\Target\TargetCollectionValidator;
|
||||
use SebastianBergmann\CodeCoverage\Test\Target\ValidationResult;
|
||||
use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize;
|
||||
use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus;
|
||||
use SebastianBergmann\CodeUnitReverseLookup\Wizard;
|
||||
|
||||
/**
|
||||
* Provides collection functionality for PHP code coverage information.
|
||||
*
|
||||
* @phpstan-type TestType array{size: string, status: string}
|
||||
* @phpstan-type TargetedLines array<non-empty-string, list<positive-int>>
|
||||
* @phpstan-type TestType = array{
|
||||
* size: string,
|
||||
* status: string,
|
||||
* }
|
||||
*/
|
||||
final class CodeCoverage
|
||||
{
|
||||
private const string UNCOVERED_FILES = 'UNCOVERED_FILES';
|
||||
private const UNCOVERED_FILES = 'UNCOVERED_FILES';
|
||||
private readonly Driver $driver;
|
||||
private readonly Filter $filter;
|
||||
private ?Mapper $targetMapper = null;
|
||||
private readonly Wizard $wizard;
|
||||
private bool $checkForUnintentionallyCoveredCode = false;
|
||||
private bool $includeUncoveredFiles = true;
|
||||
private bool $ignoreDeprecatedCode = false;
|
||||
private ?string $currentId = null;
|
||||
private ?TestSize $currentSize = null;
|
||||
private ProcessedCodeCoverageData $data;
|
||||
private bool $useAnnotationsForIgnoringCode = true;
|
||||
|
||||
/**
|
||||
* @var array<string,list<int>>
|
||||
*/
|
||||
private array $linesToBeIgnored = [];
|
||||
|
||||
/**
|
||||
* @var array<string, TestType>
|
||||
*/
|
||||
@@ -73,6 +79,7 @@ final class CodeCoverage
|
||||
$this->driver = $driver;
|
||||
$this->filter = $filter;
|
||||
$this->data = new ProcessedCodeCoverageData;
|
||||
$this->wizard = new Wizard;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +128,9 @@ final class CodeCoverage
|
||||
public function getData(bool $raw = false): ProcessedCodeCoverageData
|
||||
{
|
||||
if (!$raw) {
|
||||
$this->addUncoveredFilesFromFilter();
|
||||
if ($this->includeUncoveredFiles) {
|
||||
$this->addUncoveredFilesFromFilter();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->data;
|
||||
@@ -165,11 +174,19 @@ final class CodeCoverage
|
||||
$this->cachedReport = null;
|
||||
}
|
||||
|
||||
public function stop(bool $append = true, ?TestStatus $status = null, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null): RawCodeCoverageData
|
||||
/**
|
||||
* @param array<string,list<int>> $linesToBeIgnored
|
||||
*/
|
||||
public function stop(bool $append = true, ?TestStatus $status = null, array|false $linesToBeCovered = [], array $linesToBeUsed = [], array $linesToBeIgnored = []): RawCodeCoverageData
|
||||
{
|
||||
$data = $this->driver->stop();
|
||||
|
||||
$this->append($data, null, $append, $status, $covers, $uses);
|
||||
$this->linesToBeIgnored = array_merge_recursive(
|
||||
$this->linesToBeIgnored,
|
||||
$linesToBeIgnored,
|
||||
);
|
||||
|
||||
$this->append($data, null, $append, $status, $linesToBeCovered, $linesToBeUsed, $linesToBeIgnored);
|
||||
|
||||
$this->currentId = null;
|
||||
$this->currentSize = null;
|
||||
@@ -179,11 +196,13 @@ final class CodeCoverage
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,list<int>> $linesToBeIgnored
|
||||
*
|
||||
* @throws ReflectionException
|
||||
* @throws TestIdMissingException
|
||||
* @throws UnintentionallyCoveredCodeException
|
||||
*/
|
||||
public function append(RawCodeCoverageData $rawData, ?string $id = null, bool $append = true, ?TestStatus $status = null, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null): void
|
||||
public function append(RawCodeCoverageData $rawData, ?string $id = null, bool $append = true, ?TestStatus $status = null, array|false $linesToBeCovered = [], array $linesToBeUsed = [], array $linesToBeIgnored = []): void
|
||||
{
|
||||
if ($id === null) {
|
||||
$id = $this->currentId;
|
||||
@@ -193,32 +212,24 @@ final class CodeCoverage
|
||||
throw new TestIdMissingException;
|
||||
}
|
||||
|
||||
$this->cachedReport = null;
|
||||
|
||||
if ($status === null) {
|
||||
$status = TestStatus::unknown();
|
||||
}
|
||||
|
||||
if ($covers === null) {
|
||||
$covers = TargetCollection::fromArray([]);
|
||||
}
|
||||
|
||||
if ($uses === null) {
|
||||
$uses = TargetCollection::fromArray([]);
|
||||
}
|
||||
|
||||
$size = $this->currentSize;
|
||||
|
||||
if ($size === null) {
|
||||
$size = TestSize::unknown();
|
||||
}
|
||||
|
||||
$this->cachedReport = null;
|
||||
|
||||
$this->applyFilter($rawData);
|
||||
|
||||
$this->applyExecutableLinesFilter($rawData);
|
||||
|
||||
if ($this->useAnnotationsForIgnoringCode) {
|
||||
$this->applyIgnoredLinesFilter($rawData);
|
||||
$this->applyIgnoredLinesFilter($rawData, $linesToBeIgnored);
|
||||
}
|
||||
|
||||
$this->data->initializeUnseenData($rawData);
|
||||
@@ -231,17 +242,6 @@ final class CodeCoverage
|
||||
return;
|
||||
}
|
||||
|
||||
$linesToBeCovered = false;
|
||||
$linesToBeUsed = [];
|
||||
|
||||
if ($covers !== false) {
|
||||
$linesToBeCovered = $this->targetMapper()->mapTargets($covers);
|
||||
}
|
||||
|
||||
if ($linesToBeCovered !== false) {
|
||||
$linesToBeUsed = $this->targetMapper()->mapTargets($uses);
|
||||
}
|
||||
|
||||
$this->applyCoversAndUsesFilter(
|
||||
$rawData,
|
||||
$linesToBeCovered,
|
||||
@@ -287,6 +287,22 @@ final class CodeCoverage
|
||||
$this->checkForUnintentionallyCoveredCode = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function includeUncoveredFiles(): void
|
||||
{
|
||||
$this->includeUncoveredFiles = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function excludeUncoveredFiles(): void
|
||||
{
|
||||
$this->includeUncoveredFiles = false;
|
||||
}
|
||||
|
||||
public function enableAnnotationsForIgnoringCode(): void
|
||||
{
|
||||
$this->useAnnotationsForIgnoringCode = true;
|
||||
@@ -362,15 +378,12 @@ final class CodeCoverage
|
||||
return $this->driver->collectsBranchAndPathCoverage();
|
||||
}
|
||||
|
||||
public function validate(TargetCollection $targets): ValidationResult
|
||||
public function detectsDeadCode(): bool
|
||||
{
|
||||
return (new TargetCollectionValidator)->validate($this->targetMapper(), $targets);
|
||||
return $this->driver->detectsDeadCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param false|TargetedLines $linesToBeCovered
|
||||
* @param TargetedLines $linesToBeUsed
|
||||
*
|
||||
* @throws ReflectionException
|
||||
* @throws UnintentionallyCoveredCodeException
|
||||
*/
|
||||
@@ -397,9 +410,11 @@ final class CodeCoverage
|
||||
$rawData->removeCoverageDataForFile($fileWithNoCoverage);
|
||||
}
|
||||
|
||||
foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) {
|
||||
$rawData->keepLineCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
|
||||
$rawData->keepFunctionCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
|
||||
if (is_array($linesToBeCovered)) {
|
||||
foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) {
|
||||
$rawData->keepLineCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
|
||||
$rawData->keepFunctionCoverageDataOnlyForLines($fileToBeCovered, $includedLines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,13 +452,23 @@ final class CodeCoverage
|
||||
}
|
||||
}
|
||||
|
||||
private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void
|
||||
/**
|
||||
* @param array<string,list<int>> $linesToBeIgnored
|
||||
*/
|
||||
private function applyIgnoredLinesFilter(RawCodeCoverageData $data, array $linesToBeIgnored): void
|
||||
{
|
||||
foreach (array_keys($data->lineCoverage()) as $filename) {
|
||||
if (!$this->filter->isFile($filename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($linesToBeIgnored[$filename])) {
|
||||
$data->removeCoverageDataForLines(
|
||||
$filename,
|
||||
$linesToBeIgnored[$filename],
|
||||
);
|
||||
}
|
||||
|
||||
$data->removeCoverageDataForLines(
|
||||
$filename,
|
||||
$this->analyser()->ignoredLinesFor($filename),
|
||||
@@ -469,15 +494,13 @@ final class CodeCoverage
|
||||
$this->analyser(),
|
||||
),
|
||||
self::UNCOVERED_FILES,
|
||||
linesToBeIgnored: $this->linesToBeIgnored,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TargetedLines $linesToBeCovered
|
||||
* @param TargetedLines $linesToBeUsed
|
||||
*
|
||||
* @throws ReflectionException
|
||||
* @throws UnintentionallyCoveredCodeException
|
||||
*/
|
||||
@@ -493,7 +516,7 @@ final class CodeCoverage
|
||||
foreach ($data->lineCoverage() as $file => $_data) {
|
||||
foreach ($_data as $line => $flag) {
|
||||
if ($flag === 1 && !isset($allowedLines[$file][$line])) {
|
||||
$unintentionallyCoveredUnits[] = $this->targetMapper->lookup($file, $line);
|
||||
$unintentionallyCoveredUnits[] = $this->wizard->lookup($file, $line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -507,12 +530,6 @@ final class CodeCoverage
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TargetedLines $linesToBeCovered
|
||||
* @param TargetedLines $linesToBeUsed
|
||||
*
|
||||
* @return TargetedLines
|
||||
*/
|
||||
private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed): array
|
||||
{
|
||||
$allowedLines = [];
|
||||
@@ -595,19 +612,6 @@ final class CodeCoverage
|
||||
return $processed;
|
||||
}
|
||||
|
||||
private function targetMapper(): Mapper
|
||||
{
|
||||
if ($this->targetMapper !== null) {
|
||||
return $this->targetMapper;
|
||||
}
|
||||
|
||||
$this->targetMapper = new Mapper(
|
||||
(new MapBuilder)->build($this->filter, $this->analyser()),
|
||||
);
|
||||
|
||||
return $this->targetMapper;
|
||||
}
|
||||
|
||||
private function analyser(): FileAnalyser
|
||||
{
|
||||
if ($this->analyser !== null) {
|
||||
|
@@ -17,31 +17,13 @@ use function count;
|
||||
use function is_array;
|
||||
use function ksort;
|
||||
use SebastianBergmann\CodeCoverage\Driver\Driver;
|
||||
use SebastianBergmann\CodeCoverage\Driver\XdebugDriver;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type XdebugFunctionCoverageType from XdebugDriver
|
||||
* @phpstan-import-type XdebugFunctionCoverageType from \SebastianBergmann\CodeCoverage\Driver\XdebugDriver
|
||||
*
|
||||
* @phpstan-type TestIdType string
|
||||
* @phpstan-type FunctionCoverageDataType array{
|
||||
* branches: array<int, array{
|
||||
* op_start: int,
|
||||
* op_end: int,
|
||||
* line_start: int,
|
||||
* line_end: int,
|
||||
* hit: list<TestIdType>,
|
||||
* out: array<int, int>,
|
||||
* out_hit: array<int, int>,
|
||||
* }>,
|
||||
* paths: array<int, array{
|
||||
* path: array<int, int>,
|
||||
* hit: list<TestIdType>,
|
||||
* }>,
|
||||
* hit: list<TestIdType>
|
||||
* }
|
||||
* @phpstan-type FunctionCoverageType array<string, array<string, FunctionCoverageDataType>>
|
||||
* @phpstan-type TestIdType = string
|
||||
*/
|
||||
final class ProcessedCodeCoverageData
|
||||
{
|
||||
@@ -58,7 +40,22 @@ final class ProcessedCodeCoverageData
|
||||
* Maintains base format of raw data (@see https://xdebug.org/docs/code_coverage), but each 'hit' entry is an array
|
||||
* of testcase ids.
|
||||
*
|
||||
* @var FunctionCoverageType
|
||||
* @var array<string, array<string, array{
|
||||
* branches: array<int, array{
|
||||
* op_start: int,
|
||||
* op_end: int,
|
||||
* line_start: int,
|
||||
* line_end: int,
|
||||
* hit: list<TestIdType>,
|
||||
* out: array<int, int>,
|
||||
* out_hit: array<int, int>,
|
||||
* }>,
|
||||
* paths: array<int, array{
|
||||
* path: array<int, int>,
|
||||
* hit: list<TestIdType>,
|
||||
* }>,
|
||||
* hit: list<TestIdType>
|
||||
* }>>
|
||||
*/
|
||||
private array $functionCoverage = [];
|
||||
|
||||
@@ -219,8 +216,6 @@ final class ProcessedCodeCoverageData
|
||||
* 4 = the line has been tested
|
||||
*
|
||||
* During a merge, a higher number is better.
|
||||
*
|
||||
* @return 1|2|3|4
|
||||
*/
|
||||
private function priorityForLine(array $data, int $line): int
|
||||
{
|
||||
@@ -242,7 +237,7 @@ final class ProcessedCodeCoverageData
|
||||
/**
|
||||
* For a function we have never seen before, copy all data over and simply init the 'hit' array.
|
||||
*
|
||||
* @param FunctionCoverageDataType|XdebugFunctionCoverageType $functionData
|
||||
* @param XdebugFunctionCoverageType $functionData
|
||||
*/
|
||||
private function initPreviouslyUnseenFunction(string $file, string $functionName, array $functionData): void
|
||||
{
|
||||
@@ -262,7 +257,7 @@ final class ProcessedCodeCoverageData
|
||||
* Techniques such as mocking and where the contents of a file are different vary during tests (e.g. compiling
|
||||
* containers) mean that the functions inside a file cannot be relied upon to be static.
|
||||
*
|
||||
* @param FunctionCoverageDataType|XdebugFunctionCoverageType $functionData
|
||||
* @param XdebugFunctionCoverageType $functionData
|
||||
*/
|
||||
private function initPreviouslySeenFunction(string $file, string $functionName, array $functionData): void
|
||||
{
|
||||
|
@@ -14,7 +14,6 @@ use function array_diff_key;
|
||||
use function array_flip;
|
||||
use function array_intersect;
|
||||
use function array_intersect_key;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function file_get_contents;
|
||||
@@ -26,15 +25,14 @@ use function str_ends_with;
|
||||
use function str_starts_with;
|
||||
use function trim;
|
||||
use SebastianBergmann\CodeCoverage\Driver\Driver;
|
||||
use SebastianBergmann\CodeCoverage\Driver\XdebugDriver;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type XdebugFunctionsCoverageType from XdebugDriver
|
||||
* @phpstan-import-type XdebugCodeCoverageWithoutPathCoverageType from XdebugDriver
|
||||
* @phpstan-import-type XdebugCodeCoverageWithPathCoverageType from XdebugDriver
|
||||
* @phpstan-import-type XdebugFunctionsCoverageType from \SebastianBergmann\CodeCoverage\Driver\XdebugDriver
|
||||
* @phpstan-import-type XdebugCodeCoverageWithoutPathCoverageType from \SebastianBergmann\CodeCoverage\Driver\XdebugDriver
|
||||
* @phpstan-import-type XdebugCodeCoverageWithPathCoverageType from \SebastianBergmann\CodeCoverage\Driver\XdebugDriver
|
||||
*/
|
||||
final class RawCodeCoverageData
|
||||
{
|
||||
@@ -88,10 +86,11 @@ final class RawCodeCoverageData
|
||||
|
||||
public static function fromUncoveredFile(string $filename, FileAnalyser $analyser): self
|
||||
{
|
||||
$lineCoverage = array_map(
|
||||
static fn (): int => Driver::LINE_NOT_EXECUTED,
|
||||
$analyser->executableLinesIn($filename),
|
||||
);
|
||||
$lineCoverage = [];
|
||||
|
||||
foreach ($analyser->executableLinesIn($filename) as $line => $branch) {
|
||||
$lineCoverage[$line] = Driver::LINE_NOT_EXECUTED;
|
||||
}
|
||||
|
||||
return new self([$filename => $lineCoverage], []);
|
||||
}
|
||||
@@ -261,9 +260,6 @@ final class RawCodeCoverageData
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int>
|
||||
*/
|
||||
private function getEmptyLinesForFile(string $filename): array
|
||||
{
|
||||
if (!isset(self::$emptyLineCache[$filename])) {
|
||||
|
@@ -12,6 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Driver;
|
||||
use function sprintf;
|
||||
use SebastianBergmann\CodeCoverage\BranchAndPathCoverageNotSupportedException;
|
||||
use SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData;
|
||||
use SebastianBergmann\CodeCoverage\DeadCodeDetectionNotSupportedException;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
@@ -23,36 +24,37 @@ abstract class Driver
|
||||
*
|
||||
* @see http://xdebug.org/docs/code_coverage
|
||||
*/
|
||||
public const int LINE_NOT_EXECUTABLE = -2;
|
||||
public const LINE_NOT_EXECUTABLE = -2;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @see http://xdebug.org/docs/code_coverage
|
||||
*/
|
||||
public const int LINE_NOT_EXECUTED = -1;
|
||||
public const LINE_NOT_EXECUTED = -1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @see http://xdebug.org/docs/code_coverage
|
||||
*/
|
||||
public const int LINE_EXECUTED = 1;
|
||||
public const LINE_EXECUTED = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @see http://xdebug.org/docs/code_coverage
|
||||
*/
|
||||
public const int BRANCH_NOT_HIT = 0;
|
||||
public const BRANCH_NOT_HIT = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @see http://xdebug.org/docs/code_coverage
|
||||
*/
|
||||
public const int BRANCH_HIT = 1;
|
||||
public const BRANCH_HIT = 1;
|
||||
private bool $collectBranchAndPathCoverage = false;
|
||||
private bool $detectDeadCode = false;
|
||||
|
||||
public function canCollectBranchAndPathCoverage(): bool
|
||||
{
|
||||
@@ -86,6 +88,38 @@ abstract class Driver
|
||||
$this->collectBranchAndPathCoverage = false;
|
||||
}
|
||||
|
||||
public function canDetectDeadCode(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function detectsDeadCode(): bool
|
||||
{
|
||||
return $this->detectDeadCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DeadCodeDetectionNotSupportedException
|
||||
*/
|
||||
public function enableDeadCodeDetection(): void
|
||||
{
|
||||
if (!$this->canDetectDeadCode()) {
|
||||
throw new DeadCodeDetectionNotSupportedException(
|
||||
sprintf(
|
||||
'%s does not support dead code detection',
|
||||
$this->nameAndVersion(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$this->detectDeadCode = true;
|
||||
}
|
||||
|
||||
public function disableDeadCodeDetection(): void
|
||||
{
|
||||
$this->detectDeadCode = false;
|
||||
}
|
||||
|
||||
abstract public function nameAndVersion(): string;
|
||||
|
||||
abstract public function start(): void;
|
||||
|
@@ -38,9 +38,6 @@ final class PcovDriver extends Driver
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function start(): void
|
||||
{
|
||||
start();
|
||||
@@ -50,7 +47,6 @@ final class PcovDriver extends Driver
|
||||
{
|
||||
stop();
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
$filesToCollectCoverageFor = waiting();
|
||||
$collected = [];
|
||||
|
||||
@@ -65,7 +61,6 @@ final class PcovDriver extends Driver
|
||||
}
|
||||
|
||||
return RawCodeCoverageData::fromXdebugWithoutPathCoverage($collected);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
public function nameAndVersion(): string
|
||||
|
@@ -21,7 +21,6 @@ final class Selector
|
||||
* @throws PcovNotAvailableException
|
||||
* @throws XdebugNotAvailableException
|
||||
* @throws XdebugNotEnabledException
|
||||
* @throws XdebugVersionNotSupportedException
|
||||
*/
|
||||
public function forLineCoverage(Filter $filter): Driver
|
||||
{
|
||||
@@ -32,7 +31,11 @@ final class Selector
|
||||
}
|
||||
|
||||
if ($runtime->hasXdebug()) {
|
||||
return new XdebugDriver($filter);
|
||||
$driver = new XdebugDriver($filter);
|
||||
|
||||
$driver->enableDeadCodeDetection();
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
throw new NoCodeCoverageDriverAvailableException;
|
||||
@@ -42,13 +45,13 @@ final class Selector
|
||||
* @throws NoCodeCoverageDriverWithPathCoverageSupportAvailableException
|
||||
* @throws XdebugNotAvailableException
|
||||
* @throws XdebugNotEnabledException
|
||||
* @throws XdebugVersionNotSupportedException
|
||||
*/
|
||||
public function forLineAndPathCoverage(Filter $filter): Driver
|
||||
{
|
||||
if ((new Runtime)->hasXdebug()) {
|
||||
$driver = new XdebugDriver($filter);
|
||||
|
||||
$driver->enableDeadCodeDetection();
|
||||
$driver->enableBranchAndPathCoverage();
|
||||
|
||||
return $driver;
|
||||
|
@@ -14,8 +14,11 @@ use const XDEBUG_CC_DEAD_CODE;
|
||||
use const XDEBUG_CC_UNUSED;
|
||||
use const XDEBUG_FILTER_CODE_COVERAGE;
|
||||
use const XDEBUG_PATH_INCLUDE;
|
||||
use function explode;
|
||||
use function extension_loaded;
|
||||
use function getenv;
|
||||
use function in_array;
|
||||
use function ini_get;
|
||||
use function phpversion;
|
||||
use function version_compare;
|
||||
use function xdebug_get_code_coverage;
|
||||
@@ -31,8 +34,8 @@ use SebastianBergmann\CodeCoverage\Filter;
|
||||
*
|
||||
* @see https://xdebug.org/docs/code_coverage#xdebug_get_code_coverage
|
||||
*
|
||||
* @phpstan-type XdebugLinesCoverageType array<int, int>
|
||||
* @phpstan-type XdebugBranchCoverageType array{
|
||||
* @phpstan-type XdebugLinesCoverageType = array<int, int>
|
||||
* @phpstan-type XdebugBranchCoverageType = array{
|
||||
* op_start: int,
|
||||
* op_end: int,
|
||||
* line_start: int,
|
||||
@@ -41,32 +44,32 @@ use SebastianBergmann\CodeCoverage\Filter;
|
||||
* out: array<int, int>,
|
||||
* out_hit: array<int, int>,
|
||||
* }
|
||||
* @phpstan-type XdebugPathCoverageType array{
|
||||
* @phpstan-type XdebugPathCoverageType = array{
|
||||
* path: array<int, int>,
|
||||
* hit: int,
|
||||
* }
|
||||
* @phpstan-type XdebugFunctionCoverageType array{
|
||||
* @phpstan-type XdebugFunctionCoverageType = array{
|
||||
* branches: array<int, XdebugBranchCoverageType>,
|
||||
* paths: array<int, XdebugPathCoverageType>,
|
||||
* }
|
||||
* @phpstan-type XdebugFunctionsCoverageType array<string, XdebugFunctionCoverageType>
|
||||
* @phpstan-type XdebugPathAndBranchesCoverageType array{
|
||||
* @phpstan-type XdebugFunctionsCoverageType = array<string, XdebugFunctionCoverageType>
|
||||
* @phpstan-type XdebugPathAndBranchesCoverageType = array{
|
||||
* lines: XdebugLinesCoverageType,
|
||||
* functions: XdebugFunctionsCoverageType,
|
||||
* }
|
||||
* @phpstan-type XdebugCodeCoverageWithoutPathCoverageType array<string, XdebugLinesCoverageType>
|
||||
* @phpstan-type XdebugCodeCoverageWithPathCoverageType array<string, XdebugPathAndBranchesCoverageType>
|
||||
* @phpstan-type XdebugCodeCoverageWithoutPathCoverageType = array<string, XdebugLinesCoverageType>
|
||||
* @phpstan-type XdebugCodeCoverageWithPathCoverageType = array<string, XdebugPathAndBranchesCoverageType>
|
||||
*/
|
||||
final class XdebugDriver extends Driver
|
||||
{
|
||||
/**
|
||||
* @throws XdebugNotAvailableException
|
||||
* @throws XdebugNotEnabledException
|
||||
* @throws XdebugVersionNotSupportedException
|
||||
*/
|
||||
public function __construct(Filter $filter)
|
||||
{
|
||||
$this->ensureXdebugIsAvailable();
|
||||
$this->ensureXdebugCodeCoverageFeatureIsEnabled();
|
||||
|
||||
if (!$filter->isEmpty()) {
|
||||
xdebug_set_filter(
|
||||
@@ -82,9 +85,18 @@ final class XdebugDriver extends Driver
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDetectDeadCode(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function start(): void
|
||||
{
|
||||
$flags = XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE;
|
||||
$flags = XDEBUG_CC_UNUSED;
|
||||
|
||||
if ($this->detectsDeadCode() || $this->collectsBranchAndPathCoverage()) {
|
||||
$flags |= XDEBUG_CC_DEAD_CODE;
|
||||
}
|
||||
|
||||
if ($this->collectsBranchAndPathCoverage()) {
|
||||
$flags |= XDEBUG_CC_BRANCH_CHECK;
|
||||
@@ -115,20 +127,35 @@ final class XdebugDriver extends Driver
|
||||
|
||||
/**
|
||||
* @throws XdebugNotAvailableException
|
||||
* @throws XdebugNotEnabledException
|
||||
* @throws XdebugVersionNotSupportedException
|
||||
*/
|
||||
private function ensureXdebugIsAvailable(): void
|
||||
{
|
||||
if (!extension_loaded('xdebug')) {
|
||||
throw new XdebugNotAvailableException;
|
||||
}
|
||||
}
|
||||
|
||||
if (!version_compare(phpversion('xdebug'), '3.1', '>=')) {
|
||||
throw new XdebugVersionNotSupportedException(phpversion('xdebug'));
|
||||
/**
|
||||
* @throws XdebugNotEnabledException
|
||||
*/
|
||||
private function ensureXdebugCodeCoverageFeatureIsEnabled(): void
|
||||
{
|
||||
if (version_compare(phpversion('xdebug'), '3.1', '>=')) {
|
||||
if (!in_array('coverage', xdebug_info('mode'), true)) {
|
||||
throw new XdebugNotEnabledException;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array('coverage', xdebug_info('mode'), true)) {
|
||||
$mode = getenv('XDEBUG_MODE');
|
||||
|
||||
if ($mode === false || $mode === '') {
|
||||
$mode = ini_get('xdebug.mode');
|
||||
}
|
||||
|
||||
if ($mode === false ||
|
||||
!in_array('coverage', explode(',', $mode), true)) {
|
||||
throw new XdebugNotEnabledException;
|
||||
}
|
||||
}
|
||||
|
16
vendor/phpunit/php-code-coverage/src/Exception/DeadCodeDetectionNotSupportedException.php
vendored
Normal file
16
vendor/phpunit/php-code-coverage/src/Exception/DeadCodeDetectionNotSupportedException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?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;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
final class DeadCodeDetectionNotSupportedException extends RuntimeException implements Exception
|
||||
{
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function sprintf;
|
||||
use RuntimeException;
|
||||
use SebastianBergmann\CodeCoverage\Exception;
|
||||
|
||||
final class InvalidCodeCoverageTargetException extends RuntimeException implements Exception
|
||||
{
|
||||
public function __construct(Target $target)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'%s is not a valid target for code coverage',
|
||||
$target->description(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
<?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\Driver;
|
||||
|
||||
use function sprintf;
|
||||
use RuntimeException;
|
||||
use SebastianBergmann\CodeCoverage\Exception;
|
||||
|
||||
final class XdebugVersionNotSupportedException extends RuntimeException implements Exception
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $version
|
||||
*/
|
||||
public function __construct(string $version)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'Version %s of the Xdebug extension is not supported',
|
||||
$version,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@@ -15,24 +15,20 @@ use function str_ends_with;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
use Countable;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode;
|
||||
use SebastianBergmann\CodeCoverage\Util\Percentage;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type ProcessedFunctionType from File
|
||||
* @phpstan-import-type ProcessedClassType from File
|
||||
* @phpstan-import-type ProcessedTraitType from File
|
||||
* @phpstan-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
* @phpstan-import-type ProcessedFunctionType from \SebastianBergmann\CodeCoverage\Node\File
|
||||
* @phpstan-import-type ProcessedClassType from \SebastianBergmann\CodeCoverage\Node\File
|
||||
* @phpstan-import-type ProcessedTraitType from \SebastianBergmann\CodeCoverage\Node\File
|
||||
*/
|
||||
abstract class AbstractNode implements Countable
|
||||
{
|
||||
private readonly string $name;
|
||||
private string $pathAsString;
|
||||
|
||||
/**
|
||||
* @var non-empty-list<self>
|
||||
*/
|
||||
private array $pathAsArray;
|
||||
private readonly ?AbstractNode $parent;
|
||||
private string $id;
|
||||
@@ -65,9 +61,6 @@ abstract class AbstractNode implements Countable
|
||||
return $this->pathAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-list<self>
|
||||
*/
|
||||
public function pathAsArray(): array
|
||||
{
|
||||
return $this->pathAsArray;
|
||||
@@ -193,7 +186,10 @@ abstract class AbstractNode implements Countable
|
||||
*/
|
||||
abstract public function functions(): array;
|
||||
|
||||
abstract public function linesOfCode(): LinesOfCode;
|
||||
/**
|
||||
* @return LinesOfCodeType
|
||||
*/
|
||||
abstract public function linesOfCode(): array;
|
||||
|
||||
abstract public function numberOfExecutableLines(): int;
|
||||
|
||||
|
@@ -28,11 +28,11 @@ use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type TestType from CodeCoverage
|
||||
* @phpstan-import-type TestType from \SebastianBergmann\CodeCoverage\CodeCoverage
|
||||
*/
|
||||
final readonly class Builder
|
||||
final class Builder
|
||||
{
|
||||
private FileAnalyser $analyser;
|
||||
private readonly FileAnalyser $analyser;
|
||||
|
||||
public function __construct(FileAnalyser $analyser)
|
||||
{
|
||||
@@ -223,7 +223,6 @@ final readonly class Builder
|
||||
$paths[$i] = substr($paths[$i], 7);
|
||||
$paths[$i] = str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]);
|
||||
}
|
||||
|
||||
$paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]);
|
||||
|
||||
if (empty($paths[$i][0])) {
|
||||
|
@@ -14,10 +14,10 @@ use function sprintf;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class CrapIndex
|
||||
final class CrapIndex
|
||||
{
|
||||
private int $cyclomaticComplexity;
|
||||
private float $codeCoverage;
|
||||
private readonly int $cyclomaticComplexity;
|
||||
private readonly float $codeCoverage;
|
||||
|
||||
public function __construct(int $cyclomaticComplexity, float $codeCoverage)
|
||||
{
|
||||
|
@@ -14,16 +14,11 @@ use function assert;
|
||||
use function count;
|
||||
use IteratorAggregate;
|
||||
use RecursiveIteratorIterator;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode;
|
||||
|
||||
/**
|
||||
* @template-implements IteratorAggregate<int, AbstractNode>
|
||||
*
|
||||
* @phpstan-import-type ProcessedFunctionType from File
|
||||
* @phpstan-import-type ProcessedClassType from File
|
||||
* @phpstan-import-type ProcessedTraitType from File
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
*/
|
||||
final class Directory extends AbstractNode implements IteratorAggregate
|
||||
{
|
||||
@@ -40,23 +35,15 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
/**
|
||||
* @var list<File>
|
||||
*/
|
||||
private array $files = [];
|
||||
private array $files = [];
|
||||
private ?array $classes = null;
|
||||
private ?array $traits = null;
|
||||
private ?array $functions = null;
|
||||
|
||||
/**
|
||||
* @var ?array<string, ProcessedClassType>
|
||||
* @var null|LinesOfCodeType
|
||||
*/
|
||||
private ?array $classes = null;
|
||||
|
||||
/**
|
||||
* @var ?array<string, ProcessedTraitType>
|
||||
*/
|
||||
private ?array $traits = null;
|
||||
|
||||
/**
|
||||
* @var ?array<string, ProcessedFunctionType>
|
||||
*/
|
||||
private ?array $functions = null;
|
||||
private ?LinesOfCode $linesOfCode = null;
|
||||
private ?array $linesOfCode = null;
|
||||
private int $numFiles = -1;
|
||||
private int $numExecutableLines = -1;
|
||||
private int $numExecutedLines = -1;
|
||||
@@ -86,9 +73,6 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
return $this->numFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RecursiveIteratorIterator<Iterator<AbstractNode>>
|
||||
*/
|
||||
public function getIterator(): RecursiveIteratorIterator
|
||||
{
|
||||
return new RecursiveIteratorIterator(
|
||||
@@ -118,33 +102,21 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
$this->numExecutedLines = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<Directory>
|
||||
*/
|
||||
public function directories(): array
|
||||
{
|
||||
return $this->directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<File>
|
||||
*/
|
||||
public function files(): array
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<Directory|File>
|
||||
*/
|
||||
public function children(): array
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, ProcessedClassType>
|
||||
*/
|
||||
public function classes(): array
|
||||
{
|
||||
if ($this->classes === null) {
|
||||
@@ -161,9 +133,6 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
return $this->classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, ProcessedTraitType>
|
||||
*/
|
||||
public function traits(): array
|
||||
{
|
||||
if ($this->traits === null) {
|
||||
@@ -180,9 +149,6 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, ProcessedFunctionType>
|
||||
*/
|
||||
public function functions(): array
|
||||
{
|
||||
if ($this->functions === null) {
|
||||
@@ -199,22 +165,25 @@ final class Directory extends AbstractNode implements IteratorAggregate
|
||||
return $this->functions;
|
||||
}
|
||||
|
||||
public function linesOfCode(): LinesOfCode
|
||||
/**
|
||||
* @return LinesOfCodeType
|
||||
*/
|
||||
public function linesOfCode(): array
|
||||
{
|
||||
if ($this->linesOfCode === null) {
|
||||
$linesOfCode = 0;
|
||||
$commentLinesOfCode = 0;
|
||||
$nonCommentLinesOfCode = 0;
|
||||
$this->linesOfCode = [
|
||||
'linesOfCode' => 0,
|
||||
'commentLinesOfCode' => 0,
|
||||
'nonCommentLinesOfCode' => 0,
|
||||
];
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$childLinesOfCode = $child->linesOfCode();
|
||||
|
||||
$linesOfCode += $childLinesOfCode->linesOfCode();
|
||||
$commentLinesOfCode += $childLinesOfCode->commentLinesOfCode();
|
||||
$nonCommentLinesOfCode += $childLinesOfCode->nonCommentLinesOfCode();
|
||||
$this->linesOfCode['linesOfCode'] += $childLinesOfCode['linesOfCode'];
|
||||
$this->linesOfCode['commentLinesOfCode'] += $childLinesOfCode['commentLinesOfCode'];
|
||||
$this->linesOfCode['nonCommentLinesOfCode'] += $childLinesOfCode['nonCommentLinesOfCode'];
|
||||
}
|
||||
|
||||
$this->linesOfCode = new LinesOfCode($linesOfCode, $commentLinesOfCode, $nonCommentLinesOfCode);
|
||||
}
|
||||
|
||||
return $this->linesOfCode;
|
||||
|
124
vendor/phpunit/php-code-coverage/src/Node/File.php
vendored
124
vendor/phpunit/php-code-coverage/src/Node/File.php
vendored
@@ -12,21 +12,18 @@ namespace SebastianBergmann\CodeCoverage\Node;
|
||||
use function array_filter;
|
||||
use function count;
|
||||
use function range;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Class_;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Function_;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Method;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type TestType from CodeCoverage
|
||||
* @phpstan-import-type LinesType from FileAnalyser
|
||||
* @phpstan-import-type CodeUnitFunctionType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitMethodType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitClassType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitTraitType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
* @phpstan-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
*
|
||||
* @phpstan-type ProcessedFunctionType array{
|
||||
* @phpstan-type ProcessedFunctionType = array{
|
||||
* functionName: string,
|
||||
* namespace: string,
|
||||
* signature: string,
|
||||
@@ -43,7 +40,7 @@ use SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_;
|
||||
* crap: int|string,
|
||||
* link: string
|
||||
* }
|
||||
* @phpstan-type ProcessedMethodType array{
|
||||
* @phpstan-type ProcessedMethodType = array{
|
||||
* methodName: string,
|
||||
* visibility: string,
|
||||
* signature: string,
|
||||
@@ -60,7 +57,7 @@ use SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_;
|
||||
* crap: int|string,
|
||||
* link: string
|
||||
* }
|
||||
* @phpstan-type ProcessedClassType array{
|
||||
* @phpstan-type ProcessedClassType = array{
|
||||
* className: string,
|
||||
* namespace: string,
|
||||
* methods: array<string, ProcessedMethodType>,
|
||||
@@ -76,7 +73,7 @@ use SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_;
|
||||
* crap: int|string,
|
||||
* link: string
|
||||
* }
|
||||
* @phpstan-type ProcessedTraitType array{
|
||||
* @phpstan-type ProcessedTraitType = array{
|
||||
* traitName: string,
|
||||
* namespace: string,
|
||||
* methods: array<string, ProcessedMethodType>,
|
||||
@@ -100,10 +97,6 @@ final class File extends AbstractNode
|
||||
*/
|
||||
private array $lineCoverageData;
|
||||
private array $functionCoverageData;
|
||||
|
||||
/**
|
||||
* @var array<string, TestType>
|
||||
*/
|
||||
private readonly array $testData;
|
||||
private int $numExecutableLines = 0;
|
||||
private int $numExecutedLines = 0;
|
||||
@@ -126,7 +119,11 @@ final class File extends AbstractNode
|
||||
* @var array<string, ProcessedFunctionType>
|
||||
*/
|
||||
private array $functions = [];
|
||||
private readonly LinesOfCode $linesOfCode;
|
||||
|
||||
/**
|
||||
* @var LinesOfCodeType
|
||||
*/
|
||||
private readonly array $linesOfCode;
|
||||
private ?int $numClasses = null;
|
||||
private int $numTestedClasses = 0;
|
||||
private ?int $numTraits = null;
|
||||
@@ -136,18 +133,18 @@ final class File extends AbstractNode
|
||||
private ?int $numTestedFunctions = null;
|
||||
|
||||
/**
|
||||
* @var array<int, array|array{0: Class_, 1: string}|array{0: Function_}|array{0: Trait_, 1: string}>
|
||||
* @var array<int, array|array{0: CodeUnitClassType, 1: string}|array{0: CodeUnitFunctionType}|array{0: CodeUnitTraitType, 1: string}>
|
||||
*/
|
||||
private array $codeUnitsByLine = [];
|
||||
|
||||
/**
|
||||
* @param array<int, ?list<non-empty-string>> $lineCoverageData
|
||||
* @param array<string, TestType> $testData
|
||||
* @param array<string, Class_> $classes
|
||||
* @param array<string, Trait_> $traits
|
||||
* @param array<string, Function_> $functions
|
||||
* @param array<string, CodeUnitClassType> $classes
|
||||
* @param array<string, CodeUnitTraitType> $traits
|
||||
* @param array<string, CodeUnitFunctionType> $functions
|
||||
* @param LinesOfCodeType $linesOfCode
|
||||
*/
|
||||
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode)
|
||||
public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, array $linesOfCode)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
@@ -177,9 +174,6 @@ final class File extends AbstractNode
|
||||
return $this->functionCoverageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, TestType>
|
||||
*/
|
||||
public function testData(): array
|
||||
{
|
||||
return $this->testData;
|
||||
@@ -209,7 +203,7 @@ final class File extends AbstractNode
|
||||
return $this->functions;
|
||||
}
|
||||
|
||||
public function linesOfCode(): LinesOfCode
|
||||
public function linesOfCode(): array
|
||||
{
|
||||
return $this->linesOfCode;
|
||||
}
|
||||
@@ -366,13 +360,13 @@ final class File extends AbstractNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, Class_> $classes
|
||||
* @param array<string, Trait_> $traits
|
||||
* @param array<string, Function_> $functions
|
||||
* @param array<string, CodeUnitClassType> $classes
|
||||
* @param array<string, CodeUnitTraitType> $traits
|
||||
* @param array<string, CodeUnitFunctionType> $functions
|
||||
*/
|
||||
private function calculateStatistics(array $classes, array $traits, array $functions): void
|
||||
{
|
||||
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
|
||||
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
|
||||
$this->codeUnitsByLine[$lineNumber] = [];
|
||||
}
|
||||
|
||||
@@ -380,7 +374,7 @@ final class File extends AbstractNode
|
||||
$this->processTraits($traits);
|
||||
$this->processFunctions($functions);
|
||||
|
||||
foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) {
|
||||
foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
|
||||
if (isset($this->lineCoverageData[$lineNumber])) {
|
||||
foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
|
||||
$codeUnit['executableLines']++;
|
||||
@@ -473,7 +467,7 @@ final class File extends AbstractNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, Class_> $classes
|
||||
* @param array<string, CodeUnitClassType> $classes
|
||||
*/
|
||||
private function processClasses(array $classes): void
|
||||
{
|
||||
@@ -482,9 +476,9 @@ final class File extends AbstractNode
|
||||
foreach ($classes as $className => $class) {
|
||||
$this->classes[$className] = [
|
||||
'className' => $className,
|
||||
'namespace' => $class->namespace(),
|
||||
'namespace' => $class['namespace'],
|
||||
'methods' => [],
|
||||
'startLine' => $class->startLine(),
|
||||
'startLine' => $class['startLine'],
|
||||
'executableLines' => 0,
|
||||
'executedLines' => 0,
|
||||
'executableBranches' => 0,
|
||||
@@ -494,11 +488,11 @@ final class File extends AbstractNode
|
||||
'ccn' => 0,
|
||||
'coverage' => 0,
|
||||
'crap' => 0,
|
||||
'link' => $link . $class->startLine(),
|
||||
'link' => $link . $class['startLine'],
|
||||
];
|
||||
|
||||
foreach ($class->methods() as $methodName => $method) {
|
||||
$methodData = $this->newMethod($className, $method, $link);
|
||||
foreach ($class['methods'] as $methodName => $method) {
|
||||
$methodData = $this->newMethod($className, $methodName, $method, $link);
|
||||
$this->classes[$className]['methods'][$methodName] = $methodData;
|
||||
|
||||
$this->classes[$className]['executableBranches'] += $methodData['executableBranches'];
|
||||
@@ -511,7 +505,7 @@ final class File extends AbstractNode
|
||||
$this->numExecutablePaths += $methodData['executablePaths'];
|
||||
$this->numExecutedPaths += $methodData['executedPaths'];
|
||||
|
||||
foreach (range($method->startLine(), $method->endLine()) as $lineNumber) {
|
||||
foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
|
||||
$this->codeUnitsByLine[$lineNumber] = [
|
||||
&$this->classes[$className],
|
||||
&$this->classes[$className]['methods'][$methodName],
|
||||
@@ -522,7 +516,7 @@ final class File extends AbstractNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, Trait_> $traits
|
||||
* @param array<string, CodeUnitTraitType> $traits
|
||||
*/
|
||||
private function processTraits(array $traits): void
|
||||
{
|
||||
@@ -531,9 +525,9 @@ final class File extends AbstractNode
|
||||
foreach ($traits as $traitName => $trait) {
|
||||
$this->traits[$traitName] = [
|
||||
'traitName' => $traitName,
|
||||
'namespace' => $trait->namespace(),
|
||||
'namespace' => $trait['namespace'],
|
||||
'methods' => [],
|
||||
'startLine' => $trait->startLine(),
|
||||
'startLine' => $trait['startLine'],
|
||||
'executableLines' => 0,
|
||||
'executedLines' => 0,
|
||||
'executableBranches' => 0,
|
||||
@@ -543,11 +537,11 @@ final class File extends AbstractNode
|
||||
'ccn' => 0,
|
||||
'coverage' => 0,
|
||||
'crap' => 0,
|
||||
'link' => $link . $trait->startLine(),
|
||||
'link' => $link . $trait['startLine'],
|
||||
];
|
||||
|
||||
foreach ($trait->methods() as $methodName => $method) {
|
||||
$methodData = $this->newMethod($traitName, $method, $link);
|
||||
foreach ($trait['methods'] as $methodName => $method) {
|
||||
$methodData = $this->newMethod($traitName, $methodName, $method, $link);
|
||||
$this->traits[$traitName]['methods'][$methodName] = $methodData;
|
||||
|
||||
$this->traits[$traitName]['executableBranches'] += $methodData['executableBranches'];
|
||||
@@ -560,7 +554,7 @@ final class File extends AbstractNode
|
||||
$this->numExecutablePaths += $methodData['executablePaths'];
|
||||
$this->numExecutedPaths += $methodData['executedPaths'];
|
||||
|
||||
foreach (range($method->startLine(), $method->endLine()) as $lineNumber) {
|
||||
foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
|
||||
$this->codeUnitsByLine[$lineNumber] = [
|
||||
&$this->traits[$traitName],
|
||||
&$this->traits[$traitName]['methods'][$methodName],
|
||||
@@ -571,7 +565,7 @@ final class File extends AbstractNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, Function_> $functions
|
||||
* @param array<string, CodeUnitFunctionType> $functions
|
||||
*/
|
||||
private function processFunctions(array $functions): void
|
||||
{
|
||||
@@ -580,23 +574,23 @@ final class File extends AbstractNode
|
||||
foreach ($functions as $functionName => $function) {
|
||||
$this->functions[$functionName] = [
|
||||
'functionName' => $functionName,
|
||||
'namespace' => $function->namespace(),
|
||||
'signature' => $function->signature(),
|
||||
'startLine' => $function->startLine(),
|
||||
'endLine' => $function->endLine(),
|
||||
'namespace' => $function['namespace'],
|
||||
'signature' => $function['signature'],
|
||||
'startLine' => $function['startLine'],
|
||||
'endLine' => $function['endLine'],
|
||||
'executableLines' => 0,
|
||||
'executedLines' => 0,
|
||||
'executableBranches' => 0,
|
||||
'executedBranches' => 0,
|
||||
'executablePaths' => 0,
|
||||
'executedPaths' => 0,
|
||||
'ccn' => $function->cyclomaticComplexity(),
|
||||
'ccn' => $function['ccn'],
|
||||
'coverage' => 0,
|
||||
'crap' => 0,
|
||||
'link' => $link . $function->startLine(),
|
||||
'link' => $link . $function['startLine'],
|
||||
];
|
||||
|
||||
foreach (range($function->startLine(), $function->endLine()) as $lineNumber) {
|
||||
foreach (range($function['startLine'], $function['endLine']) as $lineNumber) {
|
||||
$this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]];
|
||||
}
|
||||
|
||||
@@ -640,29 +634,31 @@ final class File extends AbstractNode
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CodeUnitMethodType $method
|
||||
*
|
||||
* @return ProcessedMethodType
|
||||
*/
|
||||
private function newMethod(string $className, Method $method, string $link): array
|
||||
private function newMethod(string $className, string $methodName, array $method, string $link): array
|
||||
{
|
||||
$methodData = [
|
||||
'methodName' => $method->name(),
|
||||
'visibility' => $method->visibility()->value,
|
||||
'signature' => $method->signature(),
|
||||
'startLine' => $method->startLine(),
|
||||
'endLine' => $method->endLine(),
|
||||
'methodName' => $methodName,
|
||||
'visibility' => $method['visibility'],
|
||||
'signature' => $method['signature'],
|
||||
'startLine' => $method['startLine'],
|
||||
'endLine' => $method['endLine'],
|
||||
'executableLines' => 0,
|
||||
'executedLines' => 0,
|
||||
'executableBranches' => 0,
|
||||
'executedBranches' => 0,
|
||||
'executablePaths' => 0,
|
||||
'executedPaths' => 0,
|
||||
'ccn' => $method->cyclomaticComplexity(),
|
||||
'ccn' => $method['ccn'],
|
||||
'coverage' => 0,
|
||||
'crap' => 0,
|
||||
'link' => $link . $method->startLine(),
|
||||
'link' => $link . $method['startLine'],
|
||||
];
|
||||
|
||||
$key = $className . '->' . $method->name();
|
||||
$key = $className . '->' . $methodName;
|
||||
|
||||
if (isset($this->functionCoverageData[$key]['branches'])) {
|
||||
$methodData['executableBranches'] = count(
|
||||
|
@@ -9,13 +9,10 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Node;
|
||||
|
||||
use function assert;
|
||||
use function count;
|
||||
use RecursiveIterator;
|
||||
|
||||
/**
|
||||
* @template-implements RecursiveIterator<int, AbstractNode>
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Iterator implements RecursiveIterator
|
||||
@@ -32,38 +29,57 @@ final class Iterator implements RecursiveIterator
|
||||
$this->nodes = $node->children();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the Iterator to the first element.
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a current element after calls to rewind() or next().
|
||||
*/
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->position < count($this->nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of the current element.
|
||||
*/
|
||||
public function key(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current element.
|
||||
*/
|
||||
public function current(): ?AbstractNode
|
||||
{
|
||||
return $this->valid() ? $this->nodes[$this->position] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves forward to next element.
|
||||
*/
|
||||
public function next(): void
|
||||
{
|
||||
$this->position++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sub iterator for the current element.
|
||||
*/
|
||||
public function getChildren(): self
|
||||
{
|
||||
assert($this->nodes[$this->position] instanceof Directory);
|
||||
|
||||
return new self($this->nodes[$this->position]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current element has children.
|
||||
*/
|
||||
public function hasChildren(): bool
|
||||
{
|
||||
return $this->nodes[$this->position] instanceof Directory;
|
||||
|
@@ -168,8 +168,8 @@ final class Clover
|
||||
$linesOfCode = $item->linesOfCode();
|
||||
|
||||
$xmlMetrics = $xmlDocument->createElement('metrics');
|
||||
$xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
|
||||
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
|
||||
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['linesOfCode']);
|
||||
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['nonCommentLinesOfCode']);
|
||||
$xmlMetrics->setAttribute('classes', (string) $item->numberOfClassesAndTraits());
|
||||
$xmlMetrics->setAttribute('methods', (string) $item->numberOfMethods());
|
||||
$xmlMetrics->setAttribute('coveredmethods', (string) $item->numberOfTestedMethods());
|
||||
@@ -201,8 +201,8 @@ final class Clover
|
||||
|
||||
$xmlMetrics = $xmlDocument->createElement('metrics');
|
||||
$xmlMetrics->setAttribute('files', (string) count($report));
|
||||
$xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
|
||||
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
|
||||
$xmlMetrics->setAttribute('loc', (string) $linesOfCode['linesOfCode']);
|
||||
$xmlMetrics->setAttribute('ncloc', (string) $linesOfCode['nonCommentLinesOfCode']);
|
||||
$xmlMetrics->setAttribute('classes', (string) $report->numberOfClassesAndTraits());
|
||||
$xmlMetrics->setAttribute('methods', (string) $report->numberOfMethods());
|
||||
$xmlMetrics->setAttribute('coveredmethods', (string) $report->numberOfTestedMethods());
|
||||
|
@@ -153,7 +153,7 @@ final class Cobertura
|
||||
|
||||
$linesValid = $method['executableLines'];
|
||||
$linesCovered = $method['executedLines'];
|
||||
$lineRate = $linesCovered / $linesValid;
|
||||
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);
|
||||
|
||||
$branchesValid = $method['executableBranches'];
|
||||
$branchesCovered = $method['executedBranches'];
|
||||
@@ -228,7 +228,7 @@ final class Cobertura
|
||||
|
||||
$linesValid = $function['executableLines'];
|
||||
$linesCovered = $function['executedLines'];
|
||||
$lineRate = $linesCovered / $linesValid;
|
||||
$lineRate = $linesValid === 0 ? 0 : ($linesCovered / $linesValid);
|
||||
|
||||
$functionsLinesValid += $linesValid;
|
||||
$functionsLinesCovered += $linesCovered;
|
||||
|
@@ -22,9 +22,9 @@ use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
|
||||
use SebastianBergmann\CodeCoverage\Node\File;
|
||||
use SebastianBergmann\CodeCoverage\Util\Filesystem;
|
||||
|
||||
final readonly class Crap4j
|
||||
final class Crap4j
|
||||
{
|
||||
private int $threshold;
|
||||
private readonly int $threshold;
|
||||
|
||||
public function __construct(int $threshold = 30)
|
||||
{
|
||||
|
@@ -12,13 +12,13 @@ namespace SebastianBergmann\CodeCoverage\Report\Html;
|
||||
/**
|
||||
* @immutable
|
||||
*/
|
||||
final readonly class Colors
|
||||
final class Colors
|
||||
{
|
||||
private string $successLow;
|
||||
private string $successMedium;
|
||||
private string $successHigh;
|
||||
private string $warning;
|
||||
private string $danger;
|
||||
private readonly string $successLow;
|
||||
private readonly string $successMedium;
|
||||
private readonly string $successHigh;
|
||||
private readonly string $warning;
|
||||
private readonly string $danger;
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
|
@@ -15,9 +15,9 @@ use SebastianBergmann\CodeCoverage\InvalidArgumentException;
|
||||
/**
|
||||
* @immutable
|
||||
*/
|
||||
final readonly class CustomCssFile
|
||||
final class CustomCssFile
|
||||
{
|
||||
private string $path;
|
||||
private readonly string $path;
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
|
@@ -22,13 +22,13 @@ use SebastianBergmann\CodeCoverage\Util\Filesystem;
|
||||
use SebastianBergmann\Template\Exception;
|
||||
use SebastianBergmann\Template\Template;
|
||||
|
||||
final readonly class Facade
|
||||
final class Facade
|
||||
{
|
||||
private string $templatePath;
|
||||
private string $generator;
|
||||
private Colors $colors;
|
||||
private Thresholds $thresholds;
|
||||
private CustomCssFile $customCssFile;
|
||||
private readonly string $templatePath;
|
||||
private readonly string $generator;
|
||||
private readonly Colors $colors;
|
||||
private readonly Thresholds $thresholds;
|
||||
private readonly CustomCssFile $customCssFile;
|
||||
|
||||
public function __construct(string $generator = '', ?Colors $colors = null, ?Thresholds $thresholds = null, ?CustomCssFile $customCssFile = null)
|
||||
{
|
||||
|
@@ -44,9 +44,6 @@ abstract class Renderer
|
||||
$this->hasBranchCoverage = $hasBranchCoverage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, float|int|string> $data
|
||||
*/
|
||||
protected function renderItemTemplate(Template $template, array $data): string
|
||||
{
|
||||
$numSeparator = ' / ';
|
||||
@@ -174,8 +171,8 @@ abstract class Renderer
|
||||
'version' => $this->version,
|
||||
'runtime' => $this->runtimeString(),
|
||||
'generator' => $this->generator,
|
||||
'low_upper_bound' => (string) $this->thresholds->lowUpperBound(),
|
||||
'high_lower_bound' => (string) $this->thresholds->highLowerBound(),
|
||||
'low_upper_bound' => $this->thresholds->lowUpperBound(),
|
||||
'high_lower_bound' => $this->thresholds->highLowerBound(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ namespace SebastianBergmann\CodeCoverage\Report\Html;
|
||||
use function array_values;
|
||||
use function arsort;
|
||||
use function asort;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function floor;
|
||||
@@ -22,14 +21,10 @@ use function str_replace;
|
||||
use SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException;
|
||||
use SebastianBergmann\CodeCoverage\Node\AbstractNode;
|
||||
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
|
||||
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
|
||||
use SebastianBergmann\Template\Exception;
|
||||
use SebastianBergmann\Template\Template;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ProcessedClassType from FileNode
|
||||
* @phpstan-import-type ProcessedTraitType from FileNode
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Dashboard extends Renderer
|
||||
@@ -86,9 +81,7 @@ final class Dashboard extends Renderer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedClassType|ProcessedTraitType> $classes
|
||||
*
|
||||
* @return array{class: non-empty-string, method: non-empty-string}
|
||||
* Returns the data for the Class/Method Complexity charts.
|
||||
*/
|
||||
private function complexity(array $classes, string $baseLink): array
|
||||
{
|
||||
@@ -122,21 +115,14 @@ final class Dashboard extends Renderer
|
||||
];
|
||||
}
|
||||
|
||||
$class = json_encode($result['class']);
|
||||
|
||||
assert($class !== false);
|
||||
|
||||
$method = json_encode($result['method']);
|
||||
|
||||
assert($method !== false);
|
||||
|
||||
return ['class' => $class, 'method' => $method];
|
||||
return [
|
||||
'class' => json_encode($result['class']),
|
||||
'method' => json_encode($result['method']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedClassType|ProcessedTraitType> $classes
|
||||
*
|
||||
* @return array{class: non-empty-string, method: non-empty-string}
|
||||
* Returns the data for the Class / Method Coverage Distribution chart.
|
||||
*/
|
||||
private function coverageDistribution(array $classes): array
|
||||
{
|
||||
@@ -195,21 +181,14 @@ final class Dashboard extends Renderer
|
||||
}
|
||||
}
|
||||
|
||||
$class = json_encode(array_values($result['class']));
|
||||
|
||||
assert($class !== false);
|
||||
|
||||
$method = json_encode(array_values($result['method']));
|
||||
|
||||
assert($method !== false);
|
||||
|
||||
return ['class' => $class, 'method' => $method];
|
||||
return [
|
||||
'class' => json_encode(array_values($result['class'])),
|
||||
'method' => json_encode(array_values($result['method'])),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedClassType|ProcessedTraitType> $classes
|
||||
*
|
||||
* @return array{class: string, method: string}
|
||||
* Returns the classes / methods with insufficient coverage.
|
||||
*/
|
||||
private function insufficientCoverage(array $classes, string $baseLink): array
|
||||
{
|
||||
@@ -263,9 +242,7 @@ final class Dashboard extends Renderer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedClassType|ProcessedTraitType> $classes
|
||||
*
|
||||
* @return array{class: string, method: string}
|
||||
* Returns the project risks according to the CRAP index.
|
||||
*/
|
||||
private function projectRisks(array $classes, string $baseLink): array
|
||||
{
|
||||
|
@@ -108,11 +108,6 @@ use SebastianBergmann\Template\Exception;
|
||||
use SebastianBergmann\Template\Template;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ProcessedClassType from FileNode
|
||||
* @phpstan-import-type ProcessedTraitType from FileNode
|
||||
* @phpstan-import-type ProcessedMethodType from FileNode
|
||||
* @phpstan-import-type ProcessedFunctionType from FileNode
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class File extends Renderer
|
||||
@@ -120,7 +115,7 @@ final class File extends Renderer
|
||||
/**
|
||||
* @var array<int,true>
|
||||
*/
|
||||
private const array KEYWORD_TOKENS = [
|
||||
private const KEYWORD_TOKENS = [
|
||||
T_ABSTRACT => true,
|
||||
T_ARRAY => true,
|
||||
T_AS => true,
|
||||
@@ -190,13 +185,8 @@ final class File extends Renderer
|
||||
T_YIELD => true,
|
||||
T_YIELD_FROM => true,
|
||||
];
|
||||
|
||||
private const int HTML_SPECIAL_CHARS_FLAGS = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, list<string>>
|
||||
*/
|
||||
private static array $formattedSourceCache = [];
|
||||
private int $htmlSpecialCharsFlags = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE;
|
||||
|
||||
public function render(FileNode $node, string $file): void
|
||||
{
|
||||
@@ -324,9 +314,6 @@ final class File extends Renderer
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedClassType|ProcessedTraitType> $items
|
||||
*/
|
||||
private function renderTraitOrClassItems(array $items, Template $template, Template $methodItemTemplate): string
|
||||
{
|
||||
$buffer = '';
|
||||
@@ -431,9 +418,6 @@ final class File extends Renderer
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, ProcessedFunctionType> $functions
|
||||
*/
|
||||
private function renderFunctionItems(array $functions, Template $template): string
|
||||
{
|
||||
if (empty($functions)) {
|
||||
@@ -452,9 +436,6 @@ final class File extends Renderer
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProcessedFunctionType|ProcessedMethodType $item
|
||||
*/
|
||||
private function renderFunctionOrMethodItem(Template $template, array $item, string $indent = ''): string
|
||||
{
|
||||
$numMethods = 0;
|
||||
@@ -495,7 +476,7 @@ final class File extends Renderer
|
||||
'%s<a href="#%d"><abbr title="%s">%s</abbr></a>',
|
||||
$indent,
|
||||
$item['startLine'],
|
||||
htmlspecialchars($item['signature'], self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($item['signature'], $this->htmlSpecialCharsFlags),
|
||||
$item['functionName'] ?? $item['methodName'],
|
||||
),
|
||||
'numMethods' => $numMethods,
|
||||
@@ -573,7 +554,7 @@ final class File extends Renderer
|
||||
$popover = sprintf(
|
||||
' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"',
|
||||
$popoverTitle,
|
||||
htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -660,7 +641,7 @@ final class File extends Renderer
|
||||
$popover = sprintf(
|
||||
' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"',
|
||||
$popoverTitle,
|
||||
htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -750,7 +731,7 @@ final class File extends Renderer
|
||||
$popover = sprintf(
|
||||
' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"',
|
||||
$popoverTitle,
|
||||
htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -787,7 +768,7 @@ final class File extends Renderer
|
||||
}
|
||||
|
||||
if ($branchStructure !== '') { // don't show empty branches
|
||||
$branches .= '<h5 class="structure-heading"><a name="' . htmlspecialchars($methodName, self::HTML_SPECIAL_CHARS_FLAGS) . '">' . $this->abbreviateMethodName($methodName) . '</a></h5>' . "\n";
|
||||
$branches .= '<h5 class="structure-heading"><a name="' . htmlspecialchars($methodName, $this->htmlSpecialCharsFlags) . '">' . $this->abbreviateMethodName($methodName) . '</a></h5>' . "\n";
|
||||
$branches .= $branchStructure;
|
||||
}
|
||||
}
|
||||
@@ -797,9 +778,6 @@ final class File extends Renderer
|
||||
return $branchesTemplate->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $codeLines
|
||||
*/
|
||||
private function renderBranchLines(array $branch, array $codeLines, array $testData): string
|
||||
{
|
||||
$linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}');
|
||||
@@ -851,7 +829,7 @@ final class File extends Renderer
|
||||
$popover = sprintf(
|
||||
' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"',
|
||||
$popoverTitle,
|
||||
htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -896,7 +874,7 @@ final class File extends Renderer
|
||||
}
|
||||
|
||||
if ($pathStructure !== '') {
|
||||
$paths .= '<h5 class="structure-heading"><a name="' . htmlspecialchars($methodName, self::HTML_SPECIAL_CHARS_FLAGS) . '">' . $this->abbreviateMethodName($methodName) . '</a></h5>' . "\n";
|
||||
$paths .= '<h5 class="structure-heading"><a name="' . htmlspecialchars($methodName, $this->htmlSpecialCharsFlags) . '">' . $this->abbreviateMethodName($methodName) . '</a></h5>' . "\n";
|
||||
$paths .= $pathStructure;
|
||||
}
|
||||
}
|
||||
@@ -906,9 +884,6 @@ final class File extends Renderer
|
||||
return $pathsTemplate->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $codeLines
|
||||
*/
|
||||
private function renderPathLines(array $path, array $branches, array $codeLines, array $testData): string
|
||||
{
|
||||
$linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}');
|
||||
@@ -969,7 +944,7 @@ final class File extends Renderer
|
||||
$popover = sprintf(
|
||||
' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"',
|
||||
$popoverTitle,
|
||||
htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($popoverContent, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -990,7 +965,7 @@ final class File extends Renderer
|
||||
{
|
||||
$template->setVar(
|
||||
[
|
||||
'lineNumber' => (string) $lineNumber,
|
||||
'lineNumber' => $lineNumber,
|
||||
'lineContent' => $lineContent,
|
||||
'class' => $class,
|
||||
'popover' => $popover,
|
||||
@@ -1000,11 +975,6 @@ final class File extends Renderer
|
||||
return $template->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $file
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
private function loadFile(string $file): array
|
||||
{
|
||||
if (isset(self::$formattedSourceCache[$file])) {
|
||||
@@ -1025,14 +995,14 @@ final class File extends Renderer
|
||||
if ($token === '"' && $tokens[$j - 1] !== '\\') {
|
||||
$result[$i] .= sprintf(
|
||||
'<span class="string">%s</span>',
|
||||
htmlspecialchars($token, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($token, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
|
||||
$stringFlag = !$stringFlag;
|
||||
} else {
|
||||
$result[$i] .= sprintf(
|
||||
'<span class="keyword">%s</span>',
|
||||
htmlspecialchars($token, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($token, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1044,7 +1014,7 @@ final class File extends Renderer
|
||||
$value = str_replace(
|
||||
["\t", ' '],
|
||||
[' ', ' '],
|
||||
htmlspecialchars($value, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($value, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
|
||||
if ($value === "\n") {
|
||||
@@ -1143,7 +1113,7 @@ final class File extends Renderer
|
||||
return sprintf(
|
||||
'<li%s>%s</li>',
|
||||
$testCSS,
|
||||
htmlspecialchars($test, self::HTML_SPECIAL_CHARS_FLAGS),
|
||||
htmlspecialchars($test, $this->htmlSpecialCharsFlags),
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -26,27 +26,27 @@ final class Text
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const string COLOR_GREEN = "\x1b[30;42m";
|
||||
private const COLOR_GREEN = "\x1b[30;42m";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const string COLOR_YELLOW = "\x1b[30;43m";
|
||||
private const COLOR_YELLOW = "\x1b[30;43m";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const string COLOR_RED = "\x1b[37;41m";
|
||||
private const COLOR_RED = "\x1b[37;41m";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const string COLOR_HEADER = "\x1b[1;37;40m";
|
||||
private const COLOR_HEADER = "\x1b[1;37;40m";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const string COLOR_RESET = "\x1b[0m";
|
||||
private const COLOR_RESET = "\x1b[0m";
|
||||
private readonly Thresholds $thresholds;
|
||||
private readonly bool $showUncoveredFiles;
|
||||
private readonly bool $showOnlySummary;
|
||||
|
@@ -14,10 +14,10 @@ use SebastianBergmann\CodeCoverage\InvalidArgumentException;
|
||||
/**
|
||||
* @immutable
|
||||
*/
|
||||
final readonly class Thresholds
|
||||
final class Thresholds
|
||||
{
|
||||
private int $lowUpperBound;
|
||||
private int $highLowerBound;
|
||||
private readonly int $lowUpperBound;
|
||||
private readonly int $highLowerBound;
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
|
@@ -18,9 +18,9 @@ use SebastianBergmann\Environment\Runtime;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class BuildInformation
|
||||
final class BuildInformation
|
||||
{
|
||||
private DOMElement $contextNode;
|
||||
private readonly DOMElement $contextNode;
|
||||
|
||||
public function __construct(DOMElement $contextNode)
|
||||
{
|
||||
|
@@ -32,19 +32,12 @@ use SebastianBergmann\CodeCoverage\Driver\PathExistsButIsNotDirectoryException;
|
||||
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
|
||||
use SebastianBergmann\CodeCoverage\Node\AbstractNode;
|
||||
use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
|
||||
use SebastianBergmann\CodeCoverage\Node\File;
|
||||
use SebastianBergmann\CodeCoverage\Node\File as FileNode;
|
||||
use SebastianBergmann\CodeCoverage\Util\Filesystem as DirectoryUtil;
|
||||
use SebastianBergmann\CodeCoverage\Version;
|
||||
use SebastianBergmann\CodeCoverage\XmlException;
|
||||
use SebastianBergmann\Environment\Runtime;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ProcessedClassType from File
|
||||
* @phpstan-import-type ProcessedTraitType from File
|
||||
* @phpstan-import-type ProcessedFunctionType from File
|
||||
* @phpstan-import-type TestType from CodeCoverage
|
||||
*/
|
||||
final class Facade
|
||||
{
|
||||
private string $target;
|
||||
@@ -182,9 +175,6 @@ final class Facade
|
||||
$this->saveDocument($fileReport->asDom(), $file->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProcessedClassType|ProcessedTraitType $unit
|
||||
*/
|
||||
private function processUnit(array $unit, Report $report): void
|
||||
{
|
||||
if (isset($unit['className'])) {
|
||||
@@ -215,9 +205,6 @@ final class Facade
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProcessedFunctionType $function
|
||||
*/
|
||||
private function processFunction(array $function, Report $report): void
|
||||
{
|
||||
$functionObject = $report->functionObject($function['functionName']);
|
||||
@@ -228,9 +215,6 @@ final class Facade
|
||||
$functionObject->setTotals((string) $function['executableLines'], (string) $function['executedLines'], (string) $function['coverage']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, TestType> $tests
|
||||
*/
|
||||
private function processTests(array $tests): void
|
||||
{
|
||||
$testsObject = $this->project->tests();
|
||||
@@ -245,9 +229,9 @@ final class Facade
|
||||
$loc = $node->linesOfCode();
|
||||
|
||||
$totals->setNumLines(
|
||||
$loc->linesOfCode(),
|
||||
$loc->commentLinesOfCode(),
|
||||
$loc->nonCommentLinesOfCode(),
|
||||
$loc['linesOfCode'],
|
||||
$loc['commentLinesOfCode'],
|
||||
$loc['nonCommentLinesOfCode'],
|
||||
$node->numberOfExecutableLines(),
|
||||
$node->numberOfExecutedLines(),
|
||||
);
|
||||
|
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
||||
|
||||
use function assert;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
|
||||
@@ -40,8 +39,6 @@ class File
|
||||
);
|
||||
}
|
||||
|
||||
assert($totalsContainer instanceof DOMElement);
|
||||
|
||||
return new Totals($totalsContainer);
|
||||
}
|
||||
|
||||
@@ -68,8 +65,6 @@ class File
|
||||
),
|
||||
);
|
||||
|
||||
assert($lineNode instanceof DOMElement);
|
||||
|
||||
return new Coverage($lineNode, $line);
|
||||
}
|
||||
|
||||
|
@@ -14,9 +14,9 @@ use DOMElement;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Method
|
||||
final class Method
|
||||
{
|
||||
private DOMElement $contextNode;
|
||||
private readonly DOMElement $contextNode;
|
||||
|
||||
public function __construct(DOMElement $context, string $name)
|
||||
{
|
||||
|
@@ -9,7 +9,6 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
||||
|
||||
use function assert;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
|
||||
@@ -44,8 +43,6 @@ abstract class Node
|
||||
);
|
||||
}
|
||||
|
||||
assert($totalsContainer instanceof DOMElement);
|
||||
|
||||
return new Totals($totalsContainer);
|
||||
}
|
||||
|
||||
|
@@ -9,9 +9,7 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
||||
|
||||
use function assert;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
@@ -45,8 +43,6 @@ final class Project extends Node
|
||||
);
|
||||
}
|
||||
|
||||
assert($buildNode instanceof DOMElement);
|
||||
|
||||
return new BuildInformation($buildNode);
|
||||
}
|
||||
|
||||
@@ -66,8 +62,6 @@ final class Project extends Node
|
||||
);
|
||||
}
|
||||
|
||||
assert($testsNode instanceof DOMElement);
|
||||
|
||||
return new Tests($testsNode);
|
||||
}
|
||||
|
||||
|
@@ -9,11 +9,9 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
||||
|
||||
use function assert;
|
||||
use function basename;
|
||||
use function dirname;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
@@ -40,7 +38,7 @@ final class Report extends File
|
||||
return $this->dom();
|
||||
}
|
||||
|
||||
public function functionObject(string $name): Method
|
||||
public function functionObject($name): Method
|
||||
{
|
||||
$node = $this->contextNode()->appendChild(
|
||||
$this->dom()->createElementNS(
|
||||
@@ -49,17 +47,15 @@ final class Report extends File
|
||||
),
|
||||
);
|
||||
|
||||
assert($node instanceof DOMElement);
|
||||
|
||||
return new Method($node, $name);
|
||||
}
|
||||
|
||||
public function classObject(string $name): Unit
|
||||
public function classObject($name): Unit
|
||||
{
|
||||
return $this->unitObject('class', $name);
|
||||
}
|
||||
|
||||
public function traitObject(string $name): Unit
|
||||
public function traitObject($name): Unit
|
||||
{
|
||||
return $this->unitObject('trait', $name);
|
||||
}
|
||||
@@ -80,8 +76,6 @@ final class Report extends File
|
||||
);
|
||||
}
|
||||
|
||||
assert($source instanceof DOMElement);
|
||||
|
||||
return new Source($source);
|
||||
}
|
||||
|
||||
@@ -91,7 +85,7 @@ final class Report extends File
|
||||
$this->contextNode()->setAttribute('path', dirname($name));
|
||||
}
|
||||
|
||||
private function unitObject(string $tagName, string $name): Unit
|
||||
private function unitObject(string $tagName, $name): Unit
|
||||
{
|
||||
$node = $this->contextNode()->appendChild(
|
||||
$this->dom()->createElementNS(
|
||||
@@ -100,8 +94,6 @@ final class Report extends File
|
||||
),
|
||||
);
|
||||
|
||||
assert($node instanceof DOMElement);
|
||||
|
||||
return new Unit($node, $name);
|
||||
}
|
||||
}
|
||||
|
@@ -17,9 +17,9 @@ use TheSeer\Tokenizer\XMLSerializer;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Source
|
||||
final class Source
|
||||
{
|
||||
private DOMElement $context;
|
||||
private readonly DOMElement $context;
|
||||
|
||||
public function __construct(DOMElement $context)
|
||||
{
|
||||
|
@@ -11,16 +11,15 @@ namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
||||
|
||||
use function assert;
|
||||
use DOMElement;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type TestType from CodeCoverage
|
||||
* @phpstan-import-type TestType from \SebastianBergmann\CodeCoverage\CodeCoverage
|
||||
*/
|
||||
final readonly class Tests
|
||||
final class Tests
|
||||
{
|
||||
private DOMElement $contextNode;
|
||||
private readonly DOMElement $contextNode;
|
||||
|
||||
public function __construct(DOMElement $context)
|
||||
{
|
||||
|
@@ -17,14 +17,14 @@ use SebastianBergmann\CodeCoverage\Util\Percentage;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Totals
|
||||
final class Totals
|
||||
{
|
||||
private DOMNode $container;
|
||||
private DOMElement $linesNode;
|
||||
private DOMElement $methodsNode;
|
||||
private DOMElement $functionsNode;
|
||||
private DOMElement $classesNode;
|
||||
private DOMElement $traitsNode;
|
||||
private readonly DOMNode $container;
|
||||
private readonly DOMElement $linesNode;
|
||||
private readonly DOMElement $methodsNode;
|
||||
private readonly DOMElement $functionsNode;
|
||||
private readonly DOMElement $classesNode;
|
||||
private readonly DOMElement $traitsNode;
|
||||
|
||||
public function __construct(DOMElement $container)
|
||||
{
|
||||
|
@@ -15,9 +15,9 @@ use DOMElement;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Unit
|
||||
final class Unit
|
||||
{
|
||||
private DOMElement $contextNode;
|
||||
private readonly DOMElement $contextNode;
|
||||
|
||||
public function __construct(DOMElement $context, string $name)
|
||||
{
|
||||
@@ -68,8 +68,6 @@ final readonly class Unit
|
||||
),
|
||||
);
|
||||
|
||||
assert($node instanceof DOMElement);
|
||||
|
||||
return new Method($node, $name);
|
||||
}
|
||||
|
||||
|
@@ -23,17 +23,12 @@ use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-type CachedDataForFile array{
|
||||
* interfacesIn: array<string, Interface_>,
|
||||
* classesIn: array<string, Class_>,
|
||||
* traitsIn: array<string, Trait_>,
|
||||
* functionsIn: array<string, Function_>,
|
||||
* linesOfCodeFor: LinesOfCode,
|
||||
* ignoredLinesFor: LinesType,
|
||||
* executableLinesIn: LinesType
|
||||
* }
|
||||
*
|
||||
* @phpstan-import-type LinesType from FileAnalyser
|
||||
* @phpstan-import-type CodeUnitFunctionType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitMethodType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitClassType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitTraitType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
* @phpstan-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
*/
|
||||
final class CachingFileAnalyser implements FileAnalyser
|
||||
{
|
||||
@@ -42,10 +37,6 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
private readonly FileAnalyser $analyser;
|
||||
private readonly bool $useAnnotationsForIgnoringCode;
|
||||
private readonly bool $ignoreDeprecatedCode;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, CachedDataForFile>
|
||||
*/
|
||||
private array $cache = [];
|
||||
|
||||
public function __construct(string $directory, FileAnalyser $analyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
|
||||
@@ -59,19 +50,7 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Interface_>
|
||||
*/
|
||||
public function interfacesIn(string $filename): array
|
||||
{
|
||||
if (!isset($this->cache[$filename])) {
|
||||
$this->process($filename);
|
||||
}
|
||||
|
||||
return $this->cache[$filename]['interfacesIn'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Class_>
|
||||
* @return array<string, CodeUnitClassType>
|
||||
*/
|
||||
public function classesIn(string $filename): array
|
||||
{
|
||||
@@ -83,7 +62,7 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Trait_>
|
||||
* @return array<string, CodeUnitTraitType>
|
||||
*/
|
||||
public function traitsIn(string $filename): array
|
||||
{
|
||||
@@ -95,7 +74,7 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Function_>
|
||||
* @return array<string, CodeUnitFunctionType>
|
||||
*/
|
||||
public function functionsIn(string $filename): array
|
||||
{
|
||||
@@ -106,7 +85,10 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
return $this->cache[$filename]['functionsIn'];
|
||||
}
|
||||
|
||||
public function linesOfCodeFor(string $filename): LinesOfCode
|
||||
/**
|
||||
* @return LinesOfCodeType
|
||||
*/
|
||||
public function linesOfCodeFor(string $filename): array
|
||||
{
|
||||
if (!isset($this->cache[$filename])) {
|
||||
$this->process($filename);
|
||||
@@ -150,7 +132,6 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
$this->cache[$filename] = [
|
||||
'interfacesIn' => $this->analyser->interfacesIn($filename),
|
||||
'classesIn' => $this->analyser->classesIn($filename),
|
||||
'traitsIn' => $this->analyser->traitsIn($filename),
|
||||
'functionsIn' => $this->analyser->functionsIn($filename),
|
||||
@@ -162,9 +143,6 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
$this->write($filename, $this->cache[$filename]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CachedDataForFile|false
|
||||
*/
|
||||
private function read(string $filename): array|false
|
||||
{
|
||||
$cacheFile = $this->cacheFile($filename);
|
||||
@@ -175,22 +153,10 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
|
||||
return unserialize(
|
||||
file_get_contents($cacheFile),
|
||||
[
|
||||
'allowed_classes' => [
|
||||
Class_::class,
|
||||
Function_::class,
|
||||
Interface_::class,
|
||||
LinesOfCode::class,
|
||||
Method::class,
|
||||
Trait_::class,
|
||||
],
|
||||
],
|
||||
['allowed_classes' => false],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CachedDataForFile $data
|
||||
*/
|
||||
private function write(string $filename, array $data): void
|
||||
{
|
||||
file_put_contents(
|
||||
|
@@ -21,6 +21,7 @@ use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Enum_;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
@@ -31,51 +32,63 @@ use SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-type CodeUnitFunctionType = array{
|
||||
* name: string,
|
||||
* namespacedName: string,
|
||||
* namespace: string,
|
||||
* signature: string,
|
||||
* startLine: int,
|
||||
* endLine: int,
|
||||
* ccn: int
|
||||
* }
|
||||
* @phpstan-type CodeUnitMethodType = array{
|
||||
* methodName: string,
|
||||
* signature: string,
|
||||
* visibility: string,
|
||||
* startLine: int,
|
||||
* endLine: int,
|
||||
* ccn: int
|
||||
* }
|
||||
* @phpstan-type CodeUnitClassType = array{
|
||||
* name: string,
|
||||
* namespacedName: string,
|
||||
* namespace: string,
|
||||
* startLine: int,
|
||||
* endLine: int,
|
||||
* methods: array<string, CodeUnitMethodType>
|
||||
* }
|
||||
* @phpstan-type CodeUnitTraitType = array{
|
||||
* name: string,
|
||||
* namespacedName: string,
|
||||
* namespace: string,
|
||||
* startLine: int,
|
||||
* endLine: int,
|
||||
* methods: array<string, CodeUnitMethodType>
|
||||
* }
|
||||
*/
|
||||
final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $file;
|
||||
|
||||
/**
|
||||
* @var array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Interface_>
|
||||
*/
|
||||
private array $interfaces = [];
|
||||
|
||||
/**
|
||||
* @var array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Class_>
|
||||
* @var array<string, CodeUnitClassType>
|
||||
*/
|
||||
private array $classes = [];
|
||||
|
||||
/**
|
||||
* @var array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_>
|
||||
* @var array<string, CodeUnitTraitType>
|
||||
*/
|
||||
private array $traits = [];
|
||||
|
||||
/**
|
||||
* @var array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Function_>
|
||||
* @var array<string, CodeUnitFunctionType>
|
||||
*/
|
||||
private array $functions = [];
|
||||
|
||||
/**
|
||||
* @param non-empty-string $file
|
||||
*/
|
||||
public function __construct(string $file)
|
||||
public function enterNode(Node $node): void
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node): null
|
||||
{
|
||||
if ($node instanceof Interface_) {
|
||||
$this->processInterface($node);
|
||||
}
|
||||
|
||||
if ($node instanceof Class_) {
|
||||
if ($node->isAnonymous()) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processClass($node);
|
||||
@@ -85,52 +98,27 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
$this->processTrait($node);
|
||||
}
|
||||
|
||||
if (!$node instanceof Function_) {
|
||||
return null;
|
||||
if (!$node instanceof ClassMethod && !$node instanceof Function_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof ClassMethod) {
|
||||
$parentNode = $node->getAttribute('parent');
|
||||
|
||||
if ($parentNode instanceof Class_ && $parentNode->isAnonymous()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processMethod($node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processFunction($node);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function leaveNode(Node $node): null
|
||||
{
|
||||
if ($node instanceof Class_ && $node->isAnonymous()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$node instanceof Class_ && !$node instanceof Trait_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$traits = [];
|
||||
|
||||
foreach ($node->getTraitUses() as $traitUse) {
|
||||
foreach ($traitUse->traits as $trait) {
|
||||
$traits[] = $trait->toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($traits)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->postProcessClassOrTrait($node, $traits);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Interface_>
|
||||
*/
|
||||
public function interfaces(): array
|
||||
{
|
||||
return $this->interfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Class_>
|
||||
* @return array<string, CodeUnitClassType>
|
||||
*/
|
||||
public function classes(): array
|
||||
{
|
||||
@@ -138,7 +126,7 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_>
|
||||
* @return array<string, CodeUnitTraitType>
|
||||
*/
|
||||
public function traits(): array
|
||||
{
|
||||
@@ -146,7 +134,7 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, \SebastianBergmann\CodeCoverage\StaticAnalysis\Function_>
|
||||
* @return array<string, CodeUnitFunctionType>
|
||||
*/
|
||||
public function functions(): array
|
||||
{
|
||||
@@ -222,66 +210,32 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
return $type->toString();
|
||||
}
|
||||
|
||||
private function visibility(ClassMethod $node): Visibility
|
||||
private function visibility(ClassMethod $node): string
|
||||
{
|
||||
if ($node->isPrivate()) {
|
||||
return Visibility::Private;
|
||||
return 'private';
|
||||
}
|
||||
|
||||
if ($node->isProtected()) {
|
||||
return Visibility::Protected;
|
||||
return 'protected';
|
||||
}
|
||||
|
||||
return Visibility::Public;
|
||||
}
|
||||
|
||||
private function processInterface(Interface_ $node): void
|
||||
{
|
||||
$name = $node->name->toString();
|
||||
$namespacedName = $node->namespacedName->toString();
|
||||
$parentInterfaces = [];
|
||||
|
||||
foreach ($node->extends as $parentInterface) {
|
||||
$parentInterfaces[] = $parentInterface->toString();
|
||||
}
|
||||
|
||||
$this->interfaces[$namespacedName] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Interface_(
|
||||
$name,
|
||||
$namespacedName,
|
||||
$this->namespace($namespacedName, $name),
|
||||
$node->getStartLine(),
|
||||
$node->getEndLine(),
|
||||
$parentInterfaces,
|
||||
);
|
||||
return 'public';
|
||||
}
|
||||
|
||||
private function processClass(Class_ $node): void
|
||||
{
|
||||
$name = $node->name->toString();
|
||||
$namespacedName = $node->namespacedName->toString();
|
||||
$parentClass = null;
|
||||
$interfaces = [];
|
||||
|
||||
if ($node->extends instanceof Name) {
|
||||
$parentClass = $node->extends->toString();
|
||||
}
|
||||
|
||||
foreach ($node->implements as $interface) {
|
||||
$interfaces[] = $interface->toString();
|
||||
}
|
||||
|
||||
$this->classes[$namespacedName] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Class_(
|
||||
$name,
|
||||
$namespacedName,
|
||||
$this->namespace($namespacedName, $name),
|
||||
$this->file,
|
||||
$node->getStartLine(),
|
||||
$node->getEndLine(),
|
||||
$parentClass,
|
||||
$interfaces,
|
||||
[],
|
||||
$this->processMethods($node->getMethods()),
|
||||
);
|
||||
$this->classes[$namespacedName] = [
|
||||
'name' => $name,
|
||||
'namespacedName' => $namespacedName,
|
||||
'namespace' => $this->namespace($namespacedName, $name),
|
||||
'startLine' => $node->getStartLine(),
|
||||
'endLine' => $node->getEndLine(),
|
||||
'methods' => [],
|
||||
];
|
||||
}
|
||||
|
||||
private function processTrait(Trait_ $node): void
|
||||
@@ -289,39 +243,57 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
$name = $node->name->toString();
|
||||
$namespacedName = $node->namespacedName->toString();
|
||||
|
||||
$this->traits[$namespacedName] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_(
|
||||
$name,
|
||||
$namespacedName,
|
||||
$this->namespace($namespacedName, $name),
|
||||
$this->file,
|
||||
$node->getStartLine(),
|
||||
$node->getEndLine(),
|
||||
[],
|
||||
$this->processMethods($node->getMethods()),
|
||||
);
|
||||
$this->traits[$namespacedName] = [
|
||||
'name' => $name,
|
||||
'namespacedName' => $namespacedName,
|
||||
'namespace' => $this->namespace($namespacedName, $name),
|
||||
'startLine' => $node->getStartLine(),
|
||||
'endLine' => $node->getEndLine(),
|
||||
'methods' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<ClassMethod> $nodes
|
||||
*
|
||||
* @return array<non-empty-string, Method>
|
||||
*/
|
||||
private function processMethods(array $nodes): array
|
||||
private function processMethod(ClassMethod $node): void
|
||||
{
|
||||
$methods = [];
|
||||
$parentNode = $node->getAttribute('parent');
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
$methods[$node->name->toString()] = new Method(
|
||||
$node->name->toString(),
|
||||
$node->getStartLine(),
|
||||
$node->getEndLine(),
|
||||
$this->signature($node),
|
||||
$this->visibility($node),
|
||||
$this->cyclomaticComplexity($node),
|
||||
);
|
||||
if ($parentNode instanceof Interface_) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $methods;
|
||||
assert($parentNode instanceof Class_ || $parentNode instanceof Trait_ || $parentNode instanceof Enum_);
|
||||
assert(isset($parentNode->name));
|
||||
assert(isset($parentNode->namespacedName));
|
||||
assert($parentNode->namespacedName instanceof Name);
|
||||
|
||||
$parentName = $parentNode->name->toString();
|
||||
$parentNamespacedName = $parentNode->namespacedName->toString();
|
||||
|
||||
if ($parentNode instanceof Class_) {
|
||||
$storage = &$this->classes;
|
||||
} else {
|
||||
$storage = &$this->traits;
|
||||
}
|
||||
|
||||
if (!isset($storage[$parentNamespacedName])) {
|
||||
$storage[$parentNamespacedName] = [
|
||||
'name' => $parentName,
|
||||
'namespacedName' => $parentNamespacedName,
|
||||
'namespace' => $this->namespace($parentNamespacedName, $parentName),
|
||||
'startLine' => $parentNode->getStartLine(),
|
||||
'endLine' => $parentNode->getEndLine(),
|
||||
'methods' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$storage[$parentNamespacedName]['methods'][$node->name->toString()] = [
|
||||
'methodName' => $node->name->toString(),
|
||||
'signature' => $this->signature($node),
|
||||
'visibility' => $this->visibility($node),
|
||||
'startLine' => $node->getStartLine(),
|
||||
'endLine' => $node->getEndLine(),
|
||||
'ccn' => $this->cyclomaticComplexity($node),
|
||||
];
|
||||
}
|
||||
|
||||
private function processFunction(Function_ $node): void
|
||||
@@ -333,15 +305,15 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
$name = $node->name->toString();
|
||||
$namespacedName = $node->namespacedName->toString();
|
||||
|
||||
$this->functions[$namespacedName] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Function_(
|
||||
$name,
|
||||
$namespacedName,
|
||||
$this->namespace($namespacedName, $name),
|
||||
$node->getStartLine(),
|
||||
$node->getEndLine(),
|
||||
$this->signature($node),
|
||||
$this->cyclomaticComplexity($node),
|
||||
);
|
||||
$this->functions[$namespacedName] = [
|
||||
'name' => $name,
|
||||
'namespacedName' => $namespacedName,
|
||||
'namespace' => $this->namespace($namespacedName, $name),
|
||||
'signature' => $this->signature($node),
|
||||
'startLine' => $node->getStartLine(),
|
||||
'endLine' => $node->getEndLine(),
|
||||
'ccn' => $this->cyclomaticComplexity($node),
|
||||
];
|
||||
}
|
||||
|
||||
private function namespace(string $namespacedName, string $name): string
|
||||
@@ -385,44 +357,4 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
|
||||
return $node->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<non-empty-string> $traits
|
||||
*/
|
||||
private function postProcessClassOrTrait(Class_|Trait_ $node, array $traits): void
|
||||
{
|
||||
$name = $node->namespacedName->toString();
|
||||
|
||||
if ($node instanceof Class_) {
|
||||
assert(isset($this->classes[$name]));
|
||||
|
||||
$this->classes[$name] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Class_(
|
||||
$this->classes[$name]->name(),
|
||||
$this->classes[$name]->namespacedName(),
|
||||
$this->classes[$name]->namespace(),
|
||||
$this->classes[$name]->file(),
|
||||
$this->classes[$name]->startLine(),
|
||||
$this->classes[$name]->endLine(),
|
||||
$this->classes[$name]->parentClass(),
|
||||
$this->classes[$name]->interfaces(),
|
||||
$traits,
|
||||
$this->classes[$name]->methods(),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
assert(isset($this->traits[$name]));
|
||||
|
||||
$this->traits[$name] = new \SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_(
|
||||
$this->traits[$name]->name(),
|
||||
$this->traits[$name]->namespacedName(),
|
||||
$this->traits[$name]->namespace(),
|
||||
$this->traits[$name]->file(),
|
||||
$this->traits[$name]->startLine(),
|
||||
$this->traits[$name]->endLine(),
|
||||
$traits,
|
||||
$this->traits[$name]->methods(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ use PhpParser\NodeVisitorAbstract;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type LinesType from FileAnalyser
|
||||
* @phpstan-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
*/
|
||||
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
@@ -54,7 +54,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node): null
|
||||
public function enterNode(Node $node): void
|
||||
{
|
||||
foreach ($node->getComments() as $comment) {
|
||||
$commentLine = $comment->getStartLine();
|
||||
@@ -80,7 +80,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Interface_) {
|
||||
@@ -88,7 +88,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->unsets[$line] = true;
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Declare_ ||
|
||||
@@ -113,7 +113,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$node instanceof Node\Name ||
|
||||
$node instanceof Node\Param ||
|
||||
$node instanceof Node\Scalar) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\Match_) {
|
||||
@@ -125,13 +125,13 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
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 null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Enum_ ||
|
||||
@@ -176,7 +176,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
if ($isConcreteClassLike) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$hasEmptyBody = [] === $node->stmts ||
|
||||
@@ -188,15 +188,15 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
|
||||
if ($hasEmptyBody) {
|
||||
if ($node->getEndLine() === $node->getStartLine() && isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\ArrowFunction) {
|
||||
@@ -208,12 +208,12 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$endLine = $node->expr->getEndLine();
|
||||
|
||||
if ($endLine < $startLine) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch($startLine, $endLine, ++$this->nextBranch);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\Ternary) {
|
||||
@@ -226,7 +226,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\BinaryOp\Coalesce) {
|
||||
@@ -234,14 +234,14 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\If_ ||
|
||||
$node instanceof Node\Stmt\ElseIf_ ||
|
||||
$node instanceof Node\Stmt\Case_) {
|
||||
if (null === $node->cond) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch(
|
||||
@@ -250,7 +250,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
++$this->nextBranch,
|
||||
);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\For_) {
|
||||
@@ -292,7 +292,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
if (null === $startLine || null === $endLine) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch(
|
||||
@@ -301,7 +301,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
++$this->nextBranch,
|
||||
);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Foreach_) {
|
||||
@@ -311,7 +311,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
++$this->nextBranch,
|
||||
);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\While_ ||
|
||||
@@ -322,7 +322,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
++$this->nextBranch,
|
||||
);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Catch_) {
|
||||
@@ -337,7 +337,7 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
++$this->nextBranch,
|
||||
);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\CallLike) {
|
||||
@@ -349,19 +349,17 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
|
||||
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch);
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function afterTraverse(array $nodes): null
|
||||
public function afterTraverse(array $nodes): void
|
||||
{
|
||||
$lines = explode("\n", $this->source);
|
||||
|
||||
@@ -381,8 +379,6 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->executableLinesGroupedByBranch,
|
||||
$this->unsets,
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -12,31 +12,39 @@ namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-type LinesType array<int, int>
|
||||
* @phpstan-import-type CodeUnitFunctionType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitMethodType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitClassType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitTraitType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
*
|
||||
* @phpstan-type LinesOfCodeType = array{
|
||||
* linesOfCode: int,
|
||||
* commentLinesOfCode: int,
|
||||
* nonCommentLinesOfCode: int
|
||||
* }
|
||||
* @phpstan-type LinesType = array<int, int>
|
||||
*/
|
||||
interface FileAnalyser
|
||||
{
|
||||
/**
|
||||
* @return array<string, Interface_>
|
||||
*/
|
||||
public function interfacesIn(string $filename): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Class_>
|
||||
* @return array<string, CodeUnitClassType>
|
||||
*/
|
||||
public function classesIn(string $filename): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Trait_>
|
||||
* @return array<string, CodeUnitTraitType>
|
||||
*/
|
||||
public function traitsIn(string $filename): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Function_>
|
||||
* @return array<string, CodeUnitFunctionType>
|
||||
*/
|
||||
public function functionsIn(string $filename): array;
|
||||
|
||||
public function linesOfCodeFor(string $filename): LinesOfCode;
|
||||
/**
|
||||
* @return LinesOfCodeType
|
||||
*/
|
||||
public function linesOfCodeFor(string $filename): array;
|
||||
|
||||
/**
|
||||
* @return LinesType
|
||||
|
@@ -39,7 +39,7 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->ignoreDeprecated = $ignoreDeprecated;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node): null
|
||||
public function enterNode(Node $node): void
|
||||
{
|
||||
if (!$node instanceof Class_ &&
|
||||
!$node instanceof Trait_ &&
|
||||
@@ -48,11 +48,11 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
!$node instanceof ClassMethod &&
|
||||
!$node instanceof Function_ &&
|
||||
!$node instanceof Attribute) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Class_ && $node->isAnonymous()) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Class_ ||
|
||||
@@ -68,11 +68,11 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
}
|
||||
|
||||
if (!$this->useAnnotationsForIgnoringCode) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Interface_) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Attribute &&
|
||||
@@ -84,12 +84,10 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
$this->ignoredLines[] = $line;
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processDocComment($node);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -34,32 +34,32 @@ use SebastianBergmann\LinesOfCode\LineCountingVisitor;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @phpstan-import-type LinesType from FileAnalyser
|
||||
* @phpstan-import-type CodeUnitFunctionType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitMethodType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitClassType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type CodeUnitTraitType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor
|
||||
* @phpstan-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
* @phpstan-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
|
||||
*/
|
||||
final class ParsingFileAnalyser implements FileAnalyser
|
||||
{
|
||||
/**
|
||||
* @var array<string, array<string, Interface_>>
|
||||
*/
|
||||
private array $interfaces = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, Class_>>
|
||||
* @var array<string, array<string, CodeUnitClassType>>
|
||||
*/
|
||||
private array $classes = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, Trait_>>
|
||||
* @var array<string, array<string, CodeUnitTraitType>>
|
||||
*/
|
||||
private array $traits = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, Function_>>
|
||||
* @var array<string, array<string, CodeUnitFunctionType>>
|
||||
*/
|
||||
private array $functions = [];
|
||||
|
||||
/**
|
||||
* @var array<string, LinesOfCode>
|
||||
* @var array<string, LinesOfCodeType>
|
||||
*/
|
||||
private array $linesOfCode = [];
|
||||
|
||||
@@ -82,17 +82,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Interface_>
|
||||
*/
|
||||
public function interfacesIn(string $filename): array
|
||||
{
|
||||
$this->analyse($filename);
|
||||
|
||||
return $this->interfaces[$filename];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Class_>
|
||||
* @return array<string, CodeUnitClassType>
|
||||
*/
|
||||
public function classesIn(string $filename): array
|
||||
{
|
||||
@@ -102,7 +92,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Trait_>
|
||||
* @return array<string, CodeUnitTraitType>
|
||||
*/
|
||||
public function traitsIn(string $filename): array
|
||||
{
|
||||
@@ -112,7 +102,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Function_>
|
||||
* @return array<string, CodeUnitFunctionType>
|
||||
*/
|
||||
public function functionsIn(string $filename): array
|
||||
{
|
||||
@@ -121,7 +111,10 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
return $this->functions[$filename];
|
||||
}
|
||||
|
||||
public function linesOfCodeFor(string $filename): LinesOfCode
|
||||
/**
|
||||
* @return LinesOfCodeType
|
||||
*/
|
||||
public function linesOfCodeFor(string $filename): array
|
||||
{
|
||||
$this->analyse($filename);
|
||||
|
||||
@@ -153,7 +146,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
*/
|
||||
private function analyse(string $filename): void
|
||||
{
|
||||
if (isset($this->interfaces[$filename])) {
|
||||
if (isset($this->classes[$filename])) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -174,7 +167,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
assert($nodes !== null);
|
||||
|
||||
$traverser = new NodeTraverser;
|
||||
$codeUnitFindingVisitor = new CodeUnitFindingVisitor($filename);
|
||||
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
|
||||
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
|
||||
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
|
||||
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($source);
|
||||
@@ -202,7 +195,6 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$this->interfaces[$filename] = $codeUnitFindingVisitor->interfaces();
|
||||
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
|
||||
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
|
||||
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
|
||||
@@ -222,11 +214,11 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
|
||||
$result = $lineCountingVisitor->result();
|
||||
|
||||
$this->linesOfCode[$filename] = new LinesOfCode(
|
||||
$result->linesOfCode(),
|
||||
$result->commentLinesOfCode(),
|
||||
$result->nonCommentLinesOfCode(),
|
||||
);
|
||||
$this->linesOfCode[$filename] = [
|
||||
'linesOfCode' => $result->linesOfCode(),
|
||||
'commentLinesOfCode' => $result->commentLinesOfCode(),
|
||||
'nonCommentLinesOfCode' => $result->nonCommentLinesOfCode(),
|
||||
];
|
||||
}
|
||||
|
||||
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void
|
||||
|
@@ -1,174 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Class_
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $namespacedName;
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $file;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $startLine;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $endLine;
|
||||
|
||||
/**
|
||||
* @var ?non-empty-string
|
||||
*/
|
||||
private ?string $parentClass;
|
||||
|
||||
/**
|
||||
* @var list<non-empty-string>
|
||||
*/
|
||||
private array $interfaces;
|
||||
|
||||
/**
|
||||
* @var list<non-empty-string>
|
||||
*/
|
||||
private array $traits;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, Method>
|
||||
*/
|
||||
private array $methods;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param non-empty-string $namespacedName
|
||||
* @param non-empty-string $file
|
||||
* @param non-negative-int $startLine
|
||||
* @param non-negative-int $endLine
|
||||
* @param ?non-empty-string $parentClass
|
||||
* @param list<non-empty-string> $interfaces
|
||||
* @param list<non-empty-string> $traits
|
||||
* @param array<non-empty-string, Method> $methods
|
||||
*/
|
||||
public function __construct(string $name, string $namespacedName, string $namespace, string $file, int $startLine, int $endLine, ?string $parentClass, array $interfaces, array $traits, array $methods)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->namespacedName = $namespacedName;
|
||||
$this->namespace = $namespace;
|
||||
$this->file = $file;
|
||||
$this->startLine = $startLine;
|
||||
$this->endLine = $endLine;
|
||||
$this->parentClass = $parentClass;
|
||||
$this->interfaces = $interfaces;
|
||||
$this->traits = $traits;
|
||||
$this->methods = $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function namespacedName(): string
|
||||
{
|
||||
return $this->namespacedName;
|
||||
}
|
||||
|
||||
public function isNamespaced(): bool
|
||||
{
|
||||
return $this->namespace !== '';
|
||||
}
|
||||
|
||||
public function namespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function file(): string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function startLine(): int
|
||||
{
|
||||
return $this->startLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function endLine(): int
|
||||
{
|
||||
return $this->endLine;
|
||||
}
|
||||
|
||||
public function hasParent(): bool
|
||||
{
|
||||
return $this->parentClass !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?non-empty-string
|
||||
*/
|
||||
public function parentClass(): ?string
|
||||
{
|
||||
return $this->parentClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
public function interfaces(): array
|
||||
{
|
||||
return $this->interfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
public function traits(): array
|
||||
{
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, Method>
|
||||
*/
|
||||
public function methods(): array
|
||||
{
|
||||
return $this->methods;
|
||||
}
|
||||
}
|
@@ -1,124 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Function_
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $namespacedName;
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $startLine;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $endLine;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $signature;
|
||||
|
||||
/**
|
||||
* @var positive-int
|
||||
*/
|
||||
private int $cyclomaticComplexity;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param non-empty-string $namespacedName
|
||||
* @param non-negative-int $startLine
|
||||
* @param non-negative-int $endLine
|
||||
* @param non-empty-string $signature
|
||||
* @param positive-int $cyclomaticComplexity
|
||||
*/
|
||||
public function __construct(string $name, string $namespacedName, string $namespace, int $startLine, int $endLine, string $signature, int $cyclomaticComplexity)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->namespacedName = $namespacedName;
|
||||
$this->namespace = $namespace;
|
||||
$this->startLine = $startLine;
|
||||
$this->endLine = $endLine;
|
||||
$this->signature = $signature;
|
||||
$this->cyclomaticComplexity = $cyclomaticComplexity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function namespacedName(): string
|
||||
{
|
||||
return $this->namespacedName;
|
||||
}
|
||||
|
||||
public function isNamespaced(): bool
|
||||
{
|
||||
return $this->namespace !== '';
|
||||
}
|
||||
|
||||
public function namespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function startLine(): int
|
||||
{
|
||||
return $this->startLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function endLine(): int
|
||||
{
|
||||
return $this->endLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function signature(): string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return positive-int
|
||||
*/
|
||||
public function cyclomaticComplexity(): int
|
||||
{
|
||||
return $this->cyclomaticComplexity;
|
||||
}
|
||||
}
|
@@ -1,109 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Interface_
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $namespacedName;
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $startLine;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $endLine;
|
||||
|
||||
/**
|
||||
* @var list<non-empty-string>
|
||||
*/
|
||||
private array $parentInterfaces;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param non-empty-string $namespacedName
|
||||
* @param non-negative-int $startLine
|
||||
* @param non-negative-int $endLine
|
||||
* @param list<non-empty-string> $parentInterfaces
|
||||
*/
|
||||
public function __construct(string $name, string $namespacedName, string $namespace, int $startLine, int $endLine, array $parentInterfaces)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->namespacedName = $namespacedName;
|
||||
$this->namespace = $namespace;
|
||||
$this->startLine = $startLine;
|
||||
$this->endLine = $endLine;
|
||||
$this->parentInterfaces = $parentInterfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function namespacedName(): string
|
||||
{
|
||||
return $this->namespacedName;
|
||||
}
|
||||
|
||||
public function isNamespaced(): bool
|
||||
{
|
||||
return $this->namespace !== '';
|
||||
}
|
||||
|
||||
public function namespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function startLine(): int
|
||||
{
|
||||
return $this->startLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function endLine(): int
|
||||
{
|
||||
return $this->endLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
public function parentInterfaces(): array
|
||||
{
|
||||
return $this->parentInterfaces;
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class LinesOfCode
|
||||
{
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $linesOfCode;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $commentLinesOfCode;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $nonCommentLinesOfCode;
|
||||
|
||||
/**
|
||||
* @param non-negative-int $linesOfCode
|
||||
* @param non-negative-int $commentLinesOfCode
|
||||
* @param non-negative-int $nonCommentLinesOfCode
|
||||
*/
|
||||
public function __construct(int $linesOfCode, int $commentLinesOfCode, int $nonCommentLinesOfCode)
|
||||
{
|
||||
$this->linesOfCode = $linesOfCode;
|
||||
$this->commentLinesOfCode = $commentLinesOfCode;
|
||||
$this->nonCommentLinesOfCode = $nonCommentLinesOfCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function linesOfCode(): int
|
||||
{
|
||||
return $this->linesOfCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function commentLinesOfCode(): int
|
||||
{
|
||||
return $this->commentLinesOfCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function nonCommentLinesOfCode(): int
|
||||
{
|
||||
return $this->nonCommentLinesOfCode;
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Method
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $startLine;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $endLine;
|
||||
private Visibility $visibility;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $signature;
|
||||
|
||||
/**
|
||||
* @var positive-int
|
||||
*/
|
||||
private int $cyclomaticComplexity;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param non-negative-int $startLine
|
||||
* @param non-negative-int $endLine
|
||||
* @param non-empty-string $signature
|
||||
* @param positive-int $cyclomaticComplexity
|
||||
*/
|
||||
public function __construct(string $name, int $startLine, int $endLine, string $signature, Visibility $visibility, int $cyclomaticComplexity)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->startLine = $startLine;
|
||||
$this->endLine = $endLine;
|
||||
$this->signature = $signature;
|
||||
$this->visibility = $visibility;
|
||||
$this->cyclomaticComplexity = $cyclomaticComplexity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function startLine(): int
|
||||
{
|
||||
return $this->startLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function endLine(): int
|
||||
{
|
||||
return $this->endLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function signature(): string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
public function visibility(): Visibility
|
||||
{
|
||||
return $this->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return positive-int
|
||||
*/
|
||||
public function cyclomaticComplexity(): int
|
||||
{
|
||||
return $this->cyclomaticComplexity;
|
||||
}
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Trait_
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $namespacedName;
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $file;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $startLine;
|
||||
|
||||
/**
|
||||
* @var non-negative-int
|
||||
*/
|
||||
private int $endLine;
|
||||
|
||||
/**
|
||||
* @var list<non-empty-string>
|
||||
*/
|
||||
private array $traits;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, Method>
|
||||
*/
|
||||
private array $methods;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param non-empty-string $namespacedName
|
||||
* @param non-empty-string $file
|
||||
* @param non-negative-int $startLine
|
||||
* @param non-negative-int $endLine
|
||||
* @param list<non-empty-string> $traits
|
||||
* @param array<non-empty-string, Method> $methods
|
||||
*/
|
||||
public function __construct(string $name, string $namespacedName, string $namespace, string $file, int $startLine, int $endLine, array $traits, array $methods)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->namespacedName = $namespacedName;
|
||||
$this->namespace = $namespace;
|
||||
$this->file = $file;
|
||||
$this->startLine = $startLine;
|
||||
$this->endLine = $endLine;
|
||||
$this->traits = $traits;
|
||||
$this->methods = $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function namespacedName(): string
|
||||
{
|
||||
return $this->namespacedName;
|
||||
}
|
||||
|
||||
public function isNamespaced(): bool
|
||||
{
|
||||
return $this->namespace !== '';
|
||||
}
|
||||
|
||||
public function namespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function file(): string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function startLine(): int
|
||||
{
|
||||
return $this->startLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-negative-int
|
||||
*/
|
||||
public function endLine(): int
|
||||
{
|
||||
return $this->endLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
public function traits(): array
|
||||
{
|
||||
return $this->traits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, Method>
|
||||
*/
|
||||
public function methods(): array
|
||||
{
|
||||
return $this->methods;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
/*
|
||||
* This file is part of phpunit/php-code-coverage.
|
||||
*
|
||||
* (c) Sebastian Bergmann <sebastian@phpunit.de>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
/**
|
||||
* @internal This enumeration is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
enum Visibility: string
|
||||
{
|
||||
case Public = 'public';
|
||||
case Protected = 'protected';
|
||||
case Private = 'private';
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Class_ extends Target
|
||||
{
|
||||
/**
|
||||
* @var class-string
|
||||
*/
|
||||
private string $className;
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
protected function __construct(string $className)
|
||||
{
|
||||
$this->className = $className;
|
||||
}
|
||||
|
||||
public function isClass(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string
|
||||
*/
|
||||
public function className(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'classes';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Class ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class ClassesThatExtendClass extends Target
|
||||
{
|
||||
/**
|
||||
* @var class-string
|
||||
*/
|
||||
private string $className;
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
protected function __construct(string $className)
|
||||
{
|
||||
$this->className = $className;
|
||||
}
|
||||
|
||||
public function isClassesThatExtendClass(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string
|
||||
*/
|
||||
public function className(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'classesThatExtendClass';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Classes that extend class ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class ClassesThatImplementInterface extends Target
|
||||
{
|
||||
/**
|
||||
* @var class-string
|
||||
*/
|
||||
private string $interfaceName;
|
||||
|
||||
/**
|
||||
* @param class-string $interfaceName
|
||||
*/
|
||||
protected function __construct(string $interfaceName)
|
||||
{
|
||||
$this->interfaceName = $interfaceName;
|
||||
}
|
||||
|
||||
public function isClassesThatImplementInterface(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string
|
||||
*/
|
||||
public function interfaceName(): string
|
||||
{
|
||||
return $this->interfaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'classesThatImplementInterface';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->interfaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Classes that implement interface ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Function_ extends Target
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $functionName;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $functionName
|
||||
*/
|
||||
protected function __construct(string $functionName)
|
||||
{
|
||||
$this->functionName = $functionName;
|
||||
}
|
||||
|
||||
public function isFunction(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function functionName(): string
|
||||
{
|
||||
return $this->functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'functions';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Function ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,249 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function array_slice;
|
||||
use function array_unique;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function range;
|
||||
use SebastianBergmann\CodeCoverage\Filter;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Class_;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type TargetMap from Mapper
|
||||
* @phpstan-import-type TargetMapPart from Mapper
|
||||
*
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class MapBuilder
|
||||
{
|
||||
/**
|
||||
* @return TargetMap
|
||||
*/
|
||||
public function build(Filter $filter, FileAnalyser $analyser): array
|
||||
{
|
||||
$namespaces = [];
|
||||
$classes = [];
|
||||
$classDetails = [];
|
||||
$classesThatExtendClass = [];
|
||||
$classesThatImplementInterface = [];
|
||||
$traits = [];
|
||||
$methods = [];
|
||||
$functions = [];
|
||||
$reverseLookup = [];
|
||||
|
||||
foreach ($filter->files() as $file) {
|
||||
foreach ($analyser->traitsIn($file) as $trait) {
|
||||
if ($trait->isNamespaced()) {
|
||||
$this->processNamespace($namespaces, $trait->namespace(), $file, $trait->startLine(), $trait->endLine());
|
||||
}
|
||||
|
||||
$this->process($traits, $trait->namespacedName(), $file, $trait->startLine(), $trait->endLine());
|
||||
$this->processMethods($trait, $file, $methods, $reverseLookup);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($filter->files() as $file) {
|
||||
foreach ($analyser->traitsIn($file) as $trait) {
|
||||
foreach ($trait->traits() as $traitName) {
|
||||
if (!isset($traits[$traitName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = array_keys($traits[$traitName])[0];
|
||||
|
||||
if (!isset($traits[$trait->namespacedName()][$file])) {
|
||||
$traits[$trait->namespacedName()][$file] = $traits[$traitName][$file];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$traits[$trait->namespacedName()][$file] = array_unique(
|
||||
array_merge(
|
||||
$traits[$trait->namespacedName()][$file],
|
||||
$traits[$traitName][$file],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($filter->files() as $file) {
|
||||
foreach ($analyser->interfacesIn($file) as $interface) {
|
||||
$classesThatImplementInterface[$interface->namespacedName()] = [];
|
||||
}
|
||||
|
||||
foreach ($analyser->classesIn($file) as $class) {
|
||||
if ($class->isNamespaced()) {
|
||||
$this->processNamespace($namespaces, $class->namespace(), $file, $class->startLine(), $class->endLine());
|
||||
}
|
||||
|
||||
$this->process($classes, $class->namespacedName(), $file, $class->startLine(), $class->endLine());
|
||||
|
||||
foreach ($class->traits() as $traitName) {
|
||||
if (!isset($traits[$traitName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($traits[$traitName] as $file => $lines) {
|
||||
if (!isset($classes[$class->namespacedName()][$file])) {
|
||||
$classes[$class->namespacedName()][$file] = $lines;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$classes[$class->namespacedName()][$file] = array_unique(
|
||||
array_merge(
|
||||
$classes[$class->namespacedName()][$file],
|
||||
$lines,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->processMethods($class, $file, $methods, $reverseLookup);
|
||||
|
||||
$classesThatExtendClass[$class->namespacedName()] = [];
|
||||
$classDetails[] = $class;
|
||||
}
|
||||
|
||||
foreach ($analyser->functionsIn($file) as $function) {
|
||||
if ($function->isNamespaced()) {
|
||||
$this->processNamespace($namespaces, $function->namespace(), $file, $function->startLine(), $function->endLine());
|
||||
}
|
||||
|
||||
$this->process($functions, $function->namespacedName(), $file, $function->startLine(), $function->endLine());
|
||||
|
||||
foreach (range($function->startLine(), $function->endLine()) as $line) {
|
||||
$reverseLookup[$file . ':' . $line] = $function->namespacedName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_keys($namespaces) as $namespace) {
|
||||
foreach (array_keys($namespaces[$namespace]) as $file) {
|
||||
$namespaces[$namespace][$file] = array_unique($namespaces[$namespace][$file]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($classDetails as $class) {
|
||||
foreach ($class->interfaces() as $interfaceName) {
|
||||
if (!isset($classesThatImplementInterface[$interfaceName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->process($classesThatImplementInterface, $interfaceName, $class->file(), $class->startLine(), $class->endLine());
|
||||
}
|
||||
|
||||
if (!$class->hasParent()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($classesThatExtendClass[$class->parentClass()])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->process($classesThatExtendClass, $class->parentClass(), $class->file(), $class->startLine(), $class->endLine());
|
||||
}
|
||||
|
||||
foreach (array_keys($classesThatImplementInterface) as $className) {
|
||||
if ($classesThatImplementInterface[$className] !== []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($classesThatImplementInterface[$className]);
|
||||
}
|
||||
|
||||
foreach (array_keys($classesThatExtendClass) as $className) {
|
||||
if ($classesThatExtendClass[$className] !== []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($classesThatExtendClass[$className]);
|
||||
}
|
||||
|
||||
return [
|
||||
'namespaces' => $namespaces,
|
||||
'traits' => $traits,
|
||||
'classes' => $classes,
|
||||
'classesThatExtendClass' => $classesThatExtendClass,
|
||||
'classesThatImplementInterface' => $classesThatImplementInterface,
|
||||
'methods' => $methods,
|
||||
'functions' => $functions,
|
||||
'reverseLookup' => $reverseLookup,
|
||||
];
|
||||
}
|
||||
|
||||
private function processMethods(Class_|Trait_ $classOrTrait, string $file, array &$methods, array &$reverseLookup): void
|
||||
{
|
||||
foreach ($classOrTrait->methods() as $method) {
|
||||
$methodName = $classOrTrait->namespacedName() . '::' . $method->name();
|
||||
|
||||
$this->process($methods, $methodName, $file, $method->startLine(), $method->endLine());
|
||||
|
||||
foreach (range($method->startLine(), $method->endLine()) as $line) {
|
||||
$reverseLookup[$file . ':' . $line] = $methodName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TargetMapPart $data
|
||||
* @param non-empty-string $namespace
|
||||
* @param non-empty-string $file
|
||||
* @param positive-int $startLine
|
||||
* @param positive-int $endLine
|
||||
*
|
||||
* @param-out TargetMapPart $data
|
||||
*/
|
||||
private function processNamespace(array &$data, string $namespace, string $file, int $startLine, int $endLine): void
|
||||
{
|
||||
$parts = explode('\\', $namespace);
|
||||
|
||||
foreach (range(1, count($parts)) as $i) {
|
||||
$this->process($data, implode('\\', array_slice($parts, 0, $i)), $file, $startLine, $endLine);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TargetMapPart $data
|
||||
* @param non-empty-string $unit
|
||||
* @param non-empty-string $file
|
||||
* @param positive-int $startLine
|
||||
* @param positive-int $endLine
|
||||
*
|
||||
* @param-out TargetMapPart $data
|
||||
*/
|
||||
private function process(array &$data, string $unit, string $file, int $startLine, int $endLine): void
|
||||
{
|
||||
if (!isset($data[$unit])) {
|
||||
$data[$unit] = [];
|
||||
}
|
||||
|
||||
if (!isset($data[$unit][$file])) {
|
||||
$data[$unit][$file] = [];
|
||||
}
|
||||
|
||||
$data[$unit][$file] = array_merge(
|
||||
$data[$unit][$file],
|
||||
range($startLine, $endLine),
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function array_merge;
|
||||
use function array_unique;
|
||||
|
||||
/**
|
||||
* @phpstan-type TargetMap array{namespaces: TargetMapPart, traits: TargetMapPart, classes: TargetMapPart, classesThatExtendClass: TargetMapPart, classesThatImplementInterface: TargetMapPart, methods: TargetMapPart, functions: TargetMapPart, reverseLookup: ReverseLookup}
|
||||
* @phpstan-type TargetMapPart array<non-empty-string, array<non-empty-string, list<positive-int>>>
|
||||
* @phpstan-type ReverseLookup array<non-empty-string, non-empty-string>
|
||||
*
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Mapper
|
||||
{
|
||||
/**
|
||||
* @var TargetMap
|
||||
*/
|
||||
private array $map;
|
||||
|
||||
/**
|
||||
* @param TargetMap $map
|
||||
*/
|
||||
public function __construct(array $map)
|
||||
{
|
||||
$this->map = $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, list<positive-int>>
|
||||
*/
|
||||
public function mapTargets(TargetCollection $targets): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($targets as $target) {
|
||||
foreach ($this->mapTarget($target) as $file => $lines) {
|
||||
if (!isset($result[$file])) {
|
||||
$result[$file] = $lines;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[$file] = array_unique(array_merge($result[$file], $lines));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidCodeCoverageTargetException
|
||||
*
|
||||
* @return array<non-empty-string, list<positive-int>>
|
||||
*/
|
||||
public function mapTarget(Target $target): array
|
||||
{
|
||||
if (!isset($this->map[$target->key()][$target->target()])) {
|
||||
throw new InvalidCodeCoverageTargetException($target);
|
||||
}
|
||||
|
||||
return $this->map[$target->key()][$target->target()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $file
|
||||
* @param positive-int $line
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function lookup(string $file, int $line): string
|
||||
{
|
||||
$key = $file . ':' . $line;
|
||||
|
||||
if (isset($this->map['reverseLookup'][$key])) {
|
||||
return $this->map['reverseLookup'][$key];
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Method extends Target
|
||||
{
|
||||
/**
|
||||
* @var class-string
|
||||
*/
|
||||
private string $className;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $methodName;
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
* @param non-empty-string $methodName
|
||||
*/
|
||||
protected function __construct(string $className, string $methodName)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->methodName = $methodName;
|
||||
}
|
||||
|
||||
public function isMethod(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string
|
||||
*/
|
||||
public function className(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function methodName(): string
|
||||
{
|
||||
return $this->methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'methods';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->className . '::' . $this->methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Method ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Namespace_ extends Target
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $namespace;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $namespace
|
||||
*/
|
||||
protected function __construct(string $namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
public function isNamespace(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function namespace(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'namespaces';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Namespace ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
abstract class Target
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $namespace
|
||||
*/
|
||||
public static function forNamespace(string $namespace): Namespace_
|
||||
{
|
||||
return new Namespace_($namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public static function forClass(string $className): Class_
|
||||
{
|
||||
return new Class_($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
* @param non-empty-string $methodName
|
||||
*/
|
||||
public static function forMethod(string $className, string $methodName): Method
|
||||
{
|
||||
return new Method($className, $methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $interfaceName
|
||||
*/
|
||||
public static function forClassesThatImplementInterface(string $interfaceName): ClassesThatImplementInterface
|
||||
{
|
||||
return new ClassesThatImplementInterface($interfaceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public static function forClassesThatExtendClass(string $className): ClassesThatExtendClass
|
||||
{
|
||||
return new ClassesThatExtendClass($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $functionName
|
||||
*/
|
||||
public static function forFunction(string $functionName): Function_
|
||||
{
|
||||
return new Function_($functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trait-string $traitName
|
||||
*/
|
||||
public static function forTrait(string $traitName): Trait_
|
||||
{
|
||||
return new Trait_($traitName);
|
||||
}
|
||||
|
||||
public function isNamespace(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isClass(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isMethod(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isClassesThatImplementInterface(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isClassesThatExtendClass(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isFunction(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isTrait(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
abstract public function key(): string;
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
abstract public function target(): string;
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
abstract public function description(): string;
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function count;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
|
||||
/**
|
||||
* @template-implements IteratorAggregate<int, Target>
|
||||
*
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class TargetCollection implements Countable, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var list<Target>
|
||||
*/
|
||||
private array $targets;
|
||||
|
||||
/**
|
||||
* @param list<Target> $targets
|
||||
*/
|
||||
public static function fromArray(array $targets): self
|
||||
{
|
||||
return new self(...$targets);
|
||||
}
|
||||
|
||||
private function __construct(Target ...$targets)
|
||||
{
|
||||
$this->targets = $targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<Target>
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
return $this->targets;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->targets);
|
||||
}
|
||||
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return $this->count() === 0;
|
||||
}
|
||||
|
||||
public function isNotEmpty(): bool
|
||||
{
|
||||
return $this->count() > 0;
|
||||
}
|
||||
|
||||
public function getIterator(): TargetCollectionIterator
|
||||
{
|
||||
return new TargetCollectionIterator($this);
|
||||
}
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function count;
|
||||
use Iterator;
|
||||
|
||||
/**
|
||||
* @template-implements Iterator<int, Target>
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class TargetCollectionIterator implements Iterator
|
||||
{
|
||||
/**
|
||||
* @var list<Target>
|
||||
*/
|
||||
private readonly array $targets;
|
||||
private int $position = 0;
|
||||
|
||||
public function __construct(TargetCollection $metadata)
|
||||
{
|
||||
$this->targets = $metadata->asArray();
|
||||
}
|
||||
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function valid(): bool
|
||||
{
|
||||
return $this->position < count($this->targets);
|
||||
}
|
||||
|
||||
public function key(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function current(): Target
|
||||
{
|
||||
return $this->targets[$this->position];
|
||||
}
|
||||
|
||||
public function next(): void
|
||||
{
|
||||
$this->position++;
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class TargetCollectionValidator
|
||||
{
|
||||
public function validate(Mapper $mapper, TargetCollection $targets): ValidationResult
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
foreach ($targets as $target) {
|
||||
try {
|
||||
$mapper->mapTarget($target);
|
||||
} catch (InvalidCodeCoverageTargetException $e) {
|
||||
$errors[] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors === []) {
|
||||
return ValidationResult::success();
|
||||
}
|
||||
|
||||
return ValidationResult::failure(implode("\n", $errors));
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final class Trait_ extends Target
|
||||
{
|
||||
/**
|
||||
* @var trait-string
|
||||
*/
|
||||
private string $traitName;
|
||||
|
||||
/**
|
||||
* @param trait-string $traitName
|
||||
*/
|
||||
protected function __construct(string $traitName)
|
||||
{
|
||||
$this->traitName = $traitName;
|
||||
}
|
||||
|
||||
public function isTrait(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return trait-string
|
||||
*/
|
||||
public function traitName(): string
|
||||
{
|
||||
return $this->traitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function key(): string
|
||||
{
|
||||
return 'traits';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function target(): string
|
||||
{
|
||||
return $this->traitName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function description(): string
|
||||
{
|
||||
return 'Trait ' . $this->target();
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class ValidationFailure extends ValidationResult
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string
|
||||
*/
|
||||
private string $message;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $message
|
||||
*
|
||||
* @noinspection PhpMissingParentConstructorInspection
|
||||
*/
|
||||
protected function __construct(string $message)
|
||||
{
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function isFailure(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function message(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
abstract readonly class ValidationResult
|
||||
{
|
||||
public static function success(): ValidationSuccess
|
||||
{
|
||||
return new ValidationSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $message
|
||||
*/
|
||||
public static function failure(string $message): ValidationFailure
|
||||
{
|
||||
return new ValidationFailure($message);
|
||||
}
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-assert-if-true ValidationSuccess $this
|
||||
*/
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-assert-if-true ValidationFailure $this
|
||||
*/
|
||||
public function isFailure(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
<?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\Test\Target;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*
|
||||
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class ValidationSuccess extends ValidationResult
|
||||
{
|
||||
public function isSuccess(): true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -14,10 +14,10 @@ use function sprintf;
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
*/
|
||||
final readonly class Percentage
|
||||
final class Percentage
|
||||
{
|
||||
private float $fraction;
|
||||
private float $total;
|
||||
private readonly float $fraction;
|
||||
private readonly float $total;
|
||||
|
||||
public static function fromFractionAndTotal(float $fraction, float $total): self
|
||||
{
|
||||
|
@@ -19,7 +19,7 @@ final class Version
|
||||
public static function id(): string
|
||||
{
|
||||
if (self::$version === '') {
|
||||
self::$version = (new VersionId('12.0', dirname(__DIR__)))->asString();
|
||||
self::$version = (new VersionId('11.0.8', dirname(__DIR__)))->asString();
|
||||
}
|
||||
|
||||
return self::$version;
|
||||
|
Reference in New Issue
Block a user