Aggiornato Composer
This commit is contained in:
448
vendor/phpunit/php-code-coverage/ChangeLog.md
vendored
448
vendor/phpunit/php-code-coverage/ChangeLog.md
vendored
@@ -1,448 +0,0 @@
|
||||
# ChangeLog
|
||||
|
||||
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
|
||||
|
||||
## [9.2.15] - 2022-03-07
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#885](https://github.com/sebastianbergmann/php-code-coverage/issues/885): Files that have only `\r` (CR, 0x0d) EOL characters are not handled correctly
|
||||
* [#907](https://github.com/sebastianbergmann/php-code-coverage/issues/907): Line with only `return [` is not recognized as executable
|
||||
|
||||
## [9.2.14] - 2022-02-28
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#904](https://github.com/sebastianbergmann/php-code-coverage/issues/904): Lines of code containing the `match` keyword were not recognized as executable correctly
|
||||
* [#905](https://github.com/sebastianbergmann/php-code-coverage/issues/905): Lines of code in constructors were not recognized as executable correctly when constructor property promotion is used
|
||||
|
||||
## [9.2.13] - 2022-02-23
|
||||
|
||||
### Changed
|
||||
|
||||
* The contents of the static analysis sourcecode files is now used to generate the static analysis cache version identifier
|
||||
|
||||
### Fixed
|
||||
|
||||
* Reverted rename of `SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
|
||||
* Reverted rename of `SebastianBergmann\CodeCoverage\RawCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
|
||||
* The `ArrayDim`, `Cast`, and `MethodCall` nodes are now considered when determining whether a line of code is executable or not
|
||||
|
||||
## [9.2.12] - 2022-02-23 [YANKED]
|
||||
|
||||
### Changed
|
||||
|
||||
* [#898](https://github.com/sebastianbergmann/php-code-coverage/pull/898): Use content hash instead of `filemtime()` to determine cache hit/miss
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#736](https://github.com/sebastianbergmann/php-code-coverage/issues/736): HTML report generator allows invalid values for low upper bound and high lower bound
|
||||
* [#854](https://github.com/sebastianbergmann/php-code-coverage/issues/854): "Class Coverage Distribution" and "Class Complexity" graphs are not displayed at full width
|
||||
* [#897](https://github.com/sebastianbergmann/php-code-coverage/issues/897): `declare(strict_types=1)` marked as uncovered
|
||||
|
||||
## [9.2.11] - 2022-02-18
|
||||
|
||||
### Changed
|
||||
|
||||
* `CoveredFileAnalyser` and `UncoveredFileAnalyser` have been combined to `FileAnalyser`
|
||||
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.6.1, jQuery 3.6.0, and popper.js 1.16.1
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#889](https://github.com/sebastianbergmann/php-code-coverage/issues/889): Code Coverage depends on autoload order
|
||||
|
||||
## [9.2.10] - 2021-12-05
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#887](https://github.com/sebastianbergmann/php-code-coverage/issues/887): Document return type of `CodeUnitFindingVisitor::enterNode()` so that Symfony's DebugClassLoader does not trigger a deprecation warning
|
||||
|
||||
## [9.2.9] - 2021-11-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#882](https://github.com/sebastianbergmann/php-code-coverage/issues/882): PHPUnit 9.2.8 has wrong version number
|
||||
|
||||
## [9.2.8] - 2021-10-30
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#866](https://github.com/sebastianbergmann/php-code-coverage/issues/866): `CodeUnitFindingVisitor` does not handle `enum` type introduced in PHP 8.1
|
||||
* [#868](https://github.com/sebastianbergmann/php-code-coverage/pull/868): Uncovered files should be ignored unless requested
|
||||
* [#876](https://github.com/sebastianbergmann/php-code-coverage/issues/876): PCOV driver causes 2x slowdown after upgrade to PHPUnit 9.5
|
||||
|
||||
## [9.2.7] - 2021-09-17
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#860](https://github.com/sebastianbergmann/php-code-coverage/pull/860): Empty value for `XDEBUG_MODE` environment variable is not handled correctly
|
||||
|
||||
## [9.2.6] - 2021-03-28
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#846](https://github.com/sebastianbergmann/php-code-coverage/issues/846): Method name should not appear in the method signature attribute of Cobertura XML
|
||||
|
||||
## [9.2.5] - 2020-11-28
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#831](https://github.com/sebastianbergmann/php-code-coverage/issues/831): Files that do not contain a newline are not handled correctly
|
||||
|
||||
## [9.2.4] - 2020-11-27
|
||||
|
||||
### Added
|
||||
|
||||
* [#834](https://github.com/sebastianbergmann/php-code-coverage/issues/834): Support `XDEBUG_MODE` environment variable
|
||||
|
||||
## [9.2.3] - 2020-10-30
|
||||
|
||||
### Changed
|
||||
|
||||
* Bumped required version of `nikic/php-parser`
|
||||
|
||||
## [9.2.2] - 2020-10-28
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#820](https://github.com/sebastianbergmann/php-code-coverage/issues/820): Hidden dependency on PHPUnit
|
||||
|
||||
## [9.2.1] - 2020-10-26
|
||||
|
||||
### Fixed
|
||||
|
||||
* `SebastianBergmann\CodeCoverage\Exception` now correctly extends `\Throwable`
|
||||
|
||||
## [9.2.0] - 2020-10-02
|
||||
|
||||
### Added
|
||||
|
||||
* [#812](https://github.com/sebastianbergmann/php-code-coverage/pull/812): Support for Cobertura XML report format
|
||||
|
||||
### Changed
|
||||
|
||||
* Reduced the number of I/O operations performed by the static analysis cache
|
||||
|
||||
## [9.1.11] - 2020-09-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#811](https://github.com/sebastianbergmann/php-code-coverage/issues/811): `T_FN` constant is used on PHP 7.3 where it is not available
|
||||
|
||||
## [9.1.10] - 2020-09-18
|
||||
|
||||
### Added
|
||||
|
||||
* `SebastianBergmann\CodeCoverage\Driver\Selector::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Selector::forLineAndPathCoverage()` have been added
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#810](https://github.com/sebastianbergmann/php-code-coverage/issues/810): `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are marked as internal
|
||||
|
||||
### Removed
|
||||
|
||||
* `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are now deprecated
|
||||
|
||||
## [9.1.9] - 2020-09-15
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#808](https://github.com/sebastianbergmann/php-code-coverage/issues/808): `PHP Warning: Use of undefined constant T_MATCH`
|
||||
|
||||
## [9.1.8] - 2020-09-07
|
||||
|
||||
### Changed
|
||||
|
||||
* [#800](https://github.com/sebastianbergmann/php-code-coverage/pull/800): All files on the inclusion list are no longer loaded when `SebastianBergmann\CodeCoverage::start()` is called for the first time and `processUncoveredFiles` is set to `true`
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#799](https://github.com/sebastianbergmann/php-code-coverage/issues/799): Uncovered new line at end of file
|
||||
|
||||
## [9.1.7] - 2020-09-03
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed regressions introduced in versions 9.1.5 and 9.1.6
|
||||
|
||||
## [9.1.6] - 2020-08-31
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#799](https://github.com/sebastianbergmann/php-code-coverage/issues/799): Uncovered new line at end of file
|
||||
* [#803](https://github.com/sebastianbergmann/php-code-coverage/issues/803): HTML report does not sort directories and files anymore
|
||||
|
||||
## [9.1.5] - 2020-08-27
|
||||
|
||||
### Changed
|
||||
|
||||
* [#800](https://github.com/sebastianbergmann/php-code-coverage/pull/800): All files on the inclusion list are no longer loaded when `SebastianBergmann\CodeCoverage::start()` is called for the first time and `processUncoveredFiles` is set to `true`
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#797](https://github.com/sebastianbergmann/php-code-coverage/pull/797): Class name is wrongly removed from namespace name
|
||||
|
||||
## [9.1.4] - 2020-08-13
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#793](https://github.com/sebastianbergmann/php-code-coverage/issues/793): Lines with `::class` constant are not covered
|
||||
|
||||
## [9.1.3] - 2020-08-10
|
||||
|
||||
### Changed
|
||||
|
||||
* Changed PHP-Parser usage to parse sourcecode according to the PHP version we are currently running on instead of using emulative lexing
|
||||
|
||||
## [9.1.2] - 2020-08-10
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#791](https://github.com/sebastianbergmann/php-code-coverage/pull/791): Cache Warmer does not warm all caches
|
||||
|
||||
## [9.1.1] - 2020-08-10
|
||||
|
||||
### Added
|
||||
|
||||
* Added `SebastianBergmann\CodeCoverage::cacheDirectory()` method for querying where the cache writes its files
|
||||
|
||||
## [9.1.0] - 2020-08-10
|
||||
|
||||
### Added
|
||||
|
||||
* Implemented a persistent cache for information gathered using PHP-Parser based static analysis (hereinafter referred to as "cache")
|
||||
* Added `SebastianBergmann\CodeCoverage::cacheStaticAnalysis(string $cacheDirectory)` method for enabling the cache; it will write its files to `$directory`
|
||||
* Added `SebastianBergmann\CodeCoverage::doNotCacheStaticAnalysis` method for disabling the cache
|
||||
* Added `SebastianBergmann\CodeCoverage::cachesStaticAnalysis()` method for querying whether the cache is enabled
|
||||
* Added `SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer::warmCache()` method for warming the cache
|
||||
|
||||
## [9.0.0] - 2020-08-07
|
||||
|
||||
### Added
|
||||
|
||||
* [#761](https://github.com/sebastianbergmann/php-code-coverage/pull/761): Support for Branch Coverage and Path Coverage
|
||||
* Added `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` for selecting the best available driver for line coverage
|
||||
* Added `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` for selecting the best available driver for path coverage
|
||||
* This component is now supported on PHP 8
|
||||
* This component now supports Xdebug 3
|
||||
|
||||
### Changed
|
||||
|
||||
* [#746](https://github.com/sebastianbergmann/php-code-coverage/pull/746): Remove some ancient workarounds for very old Xdebug versions
|
||||
* [#747](https://github.com/sebastianbergmann/php-code-coverage/pull/747): Use native filtering in PCOV and Xdebug drivers
|
||||
* [#748](https://github.com/sebastianbergmann/php-code-coverage/pull/748): Store raw code coverage in value objects instead of arrays
|
||||
* [#749](https://github.com/sebastianbergmann/php-code-coverage/pull/749): Store processed code coverage in value objects instead of arrays
|
||||
* [#752](https://github.com/sebastianbergmann/php-code-coverage/pull/752): Rework how code coverage settings are propagated to the driver
|
||||
* [#754](https://github.com/sebastianbergmann/php-code-coverage/pull/754): Implement collection of raw branch and path coverage
|
||||
* [#755](https://github.com/sebastianbergmann/php-code-coverage/pull/755): Implement processing of raw branch and path coverage
|
||||
* [#756](https://github.com/sebastianbergmann/php-code-coverage/pull/756): Improve handling of uncovered files
|
||||
* `SebastianBergmann\CodeCoverage\Filter::addDirectoryToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeDirectory()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::addFilesToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFiles()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::addFileToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFile()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::removeDirectoryFromWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::excludeDirectory()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::removeFileFromWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::excludeFile()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::isFiltered()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::isExcluded()`
|
||||
* `SebastianBergmann\CodeCoverage\Filter::getWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::files()`
|
||||
* The arguments for `CodeCoverage::__construct()` are no longer optional
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#700](https://github.com/sebastianbergmann/php-code-coverage/pull/700): Throw an exception if code coverage fails to write to disk
|
||||
|
||||
### Removed
|
||||
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCacheTokens()` and `SebastianBergmann\CodeCoverage\CodeCoverage::getCacheTokens()` have been removed
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForUnintentionallyCoveredCode()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableCheckForUnintentionallyCoveredCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableCheckForUnintentionallyCoveredCode()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setSubclassesExcludedFromUnintentionallyCoveredCodeCheck()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setAddUncoveredFilesFromWhitelist()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::includeUncoveredFiles()` or `SebastianBergmann\CodeCoverage\CodeCoverage::excludeUncoveredFiles()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setProcessUncoveredFiles()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::processUncoveredFiles()` or `SebastianBergmann\CodeCoverage\CodeCoverage::doNotProcessUncoveredFiles()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setIgnoreDeprecatedCode()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::ignoreDeprecatedCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::doNotIgnoreDeprecatedCode()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setDisableIgnoredLines()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableAnnotationsForIgnoringCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableAnnotationsForIgnoringCode()` instead
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForMissingCoversAnnotation()` has been removed
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForUnexecutedCoveredCode()` has been removed
|
||||
* `SebastianBergmann\CodeCoverage\CodeCoverage::setForceCoversAnnotation()` has been removed
|
||||
* `SebastianBergmann\CodeCoverage\Filter::hasWhitelist()` has been removed, please use `SebastianBergmann\CodeCoverage\Filter::isEmpty()` instead
|
||||
* `SebastianBergmann\CodeCoverage\Filter::getWhitelistedFiles()` has been removed
|
||||
* `SebastianBergmann\CodeCoverage\Filter::setWhitelistedFiles()` has been removed
|
||||
|
||||
## [8.0.2] - 2020-05-23
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#750](https://github.com/sebastianbergmann/php-code-coverage/pull/750): Inconsistent handling of namespaces
|
||||
* [#751](https://github.com/sebastianbergmann/php-code-coverage/pull/751): Dead code is not highlighted correctly
|
||||
* [#753](https://github.com/sebastianbergmann/php-code-coverage/issues/753): Do not use `$_SERVER['REQUEST_TIME']` because the test(ed) code might unset it
|
||||
|
||||
## [8.0.1] - 2020-02-19
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#731](https://github.com/sebastianbergmann/php-code-coverage/pull/731): Confusing footer in the HTML report
|
||||
|
||||
## [8.0.0] - 2020-02-07
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#721](https://github.com/sebastianbergmann/php-code-coverage/pull/721): Workaround for PHP bug [#79191](https://bugs.php.net/bug.php?id=79191)
|
||||
|
||||
### Removed
|
||||
|
||||
* This component is no longer supported on PHP 7.2
|
||||
|
||||
## [7.0.15] - 2021-07-26
|
||||
|
||||
### Changed
|
||||
|
||||
* Bumped required version of php-token-stream
|
||||
|
||||
## [7.0.14] - 2020-12-02
|
||||
|
||||
### Changed
|
||||
|
||||
* [#837](https://github.com/sebastianbergmann/php-code-coverage/issues/837): Allow version 4 of php-token-stream
|
||||
|
||||
## [7.0.13] - 2020-11-30
|
||||
|
||||
### Changed
|
||||
|
||||
* Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` to allow installation of this version of this library on PHP 8. However, this version of this library does not work on PHP 8. PHPUnit 8.5, which uses this version of this library, does not call into this library and instead shows a message that code coverage functionality is not available for PHPUnit 8.5 on PHP 8.
|
||||
|
||||
## [7.0.12] - 2020-11-27
|
||||
|
||||
### Added
|
||||
|
||||
* [#834](https://github.com/sebastianbergmann/php-code-coverage/issues/834): Support `XDEBUG_MODE` environment variable
|
||||
|
||||
## [7.0.11] - 2020-11-27
|
||||
|
||||
### Added
|
||||
|
||||
* Support for Xdebug 3
|
||||
|
||||
## [7.0.10] - 2019-11-20
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#710](https://github.com/sebastianbergmann/php-code-coverage/pull/710): Code Coverage does not work in PhpStorm
|
||||
|
||||
## [7.0.9] - 2019-11-20
|
||||
|
||||
### Changed
|
||||
|
||||
* [#709](https://github.com/sebastianbergmann/php-code-coverage/pull/709): Prioritize PCOV over Xdebug
|
||||
|
||||
## [7.0.8] - 2019-09-17
|
||||
|
||||
### Changed
|
||||
|
||||
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.1, jQuery 3.4.1, and popper.js 1.15.0
|
||||
|
||||
## [7.0.7] - 2019-07-25
|
||||
|
||||
### Changed
|
||||
|
||||
* Bumped required version of php-token-stream
|
||||
|
||||
## [7.0.6] - 2019-07-08
|
||||
|
||||
### Changed
|
||||
|
||||
* Bumped required version of php-token-stream
|
||||
|
||||
## [7.0.5] - 2019-06-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#681](https://github.com/sebastianbergmann/php-code-coverage/pull/681): `use function` statements are not ignored
|
||||
|
||||
## [7.0.4] - 2019-05-29
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#682](https://github.com/sebastianbergmann/php-code-coverage/pull/682): Code that is not executed is reported as being executed when using PCOV
|
||||
|
||||
## [7.0.3] - 2019-02-26
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#671](https://github.com/sebastianbergmann/php-code-coverage/issues/671): `TypeError` when directory name is a number
|
||||
|
||||
## [7.0.2] - 2019-02-15
|
||||
|
||||
### Changed
|
||||
|
||||
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.0
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#667](https://github.com/sebastianbergmann/php-code-coverage/pull/667): `TypeError` in PHP reporter
|
||||
|
||||
## [7.0.1] - 2019-02-01
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#664](https://github.com/sebastianbergmann/php-code-coverage/issues/664): `TypeError` when whitelisted file does not exist
|
||||
|
||||
## [7.0.0] - 2019-02-01
|
||||
|
||||
### Added
|
||||
|
||||
* [#663](https://github.com/sebastianbergmann/php-code-coverage/pull/663): Support for PCOV
|
||||
|
||||
### Fixed
|
||||
|
||||
* [#654](https://github.com/sebastianbergmann/php-code-coverage/issues/654): HTML report fails to load assets
|
||||
* [#655](https://github.com/sebastianbergmann/php-code-coverage/issues/655): Popin pops in outside of screen
|
||||
|
||||
### Removed
|
||||
|
||||
* This component is no longer supported on PHP 7.1
|
||||
|
||||
[9.2.15]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.14...9.2.15
|
||||
[9.2.14]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.13...9.2.14
|
||||
[9.2.13]: https://github.com/sebastianbergmann/php-code-coverage/compare/c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631...9.2.13
|
||||
[9.2.12]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.11...c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631
|
||||
[9.2.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.10...9.2.11
|
||||
[9.2.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.9...9.2.10
|
||||
[9.2.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.8...9.2.9
|
||||
[9.2.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.7...9.2.8
|
||||
[9.2.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.6...9.2.7
|
||||
[9.2.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.5...9.2.6
|
||||
[9.2.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.4...9.2.5
|
||||
[9.2.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.3...9.2.4
|
||||
[9.2.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.2...9.2.3
|
||||
[9.2.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.1...9.2.2
|
||||
[9.2.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.0...9.2.1
|
||||
[9.2.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.11...9.2.0
|
||||
[9.1.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.10...9.1.11
|
||||
[9.1.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.9...9.1.10
|
||||
[9.1.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.8...9.1.9
|
||||
[9.1.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.7...9.1.8
|
||||
[9.1.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.6...9.1.7
|
||||
[9.1.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.5...9.1.6
|
||||
[9.1.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.4...9.1.5
|
||||
[9.1.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.3...9.1.4
|
||||
[9.1.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.2...9.1.3
|
||||
[9.1.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.1...9.1.2
|
||||
[9.1.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.0...9.1.1
|
||||
[9.1.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.0.0...9.1.0
|
||||
[9.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0...9.0.0
|
||||
[8.0.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0.1...8.0.2
|
||||
[8.0.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0.0...8.0.1
|
||||
[8.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.10...8.0.0
|
||||
[7.0.15]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.14...7.0.15
|
||||
[7.0.14]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.13...7.0.14
|
||||
[7.0.13]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.12...7.0.13
|
||||
[7.0.12]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.11...7.0.12
|
||||
[7.0.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.10...7.0.11
|
||||
[7.0.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.9...7.0.10
|
||||
[7.0.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.8...7.0.9
|
||||
[7.0.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.7...7.0.8
|
||||
[7.0.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.6...7.0.7
|
||||
[7.0.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.5...7.0.6
|
||||
[7.0.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.4...7.0.5
|
||||
[7.0.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.3...7.0.4
|
||||
[7.0.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.2...7.0.3
|
||||
[7.0.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.1...7.0.2
|
||||
[7.0.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.0...7.0.1
|
||||
[7.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/6.1.4...7.0.0
|
||||
46
vendor/phpunit/php-code-coverage/LICENSE
vendored
46
vendor/phpunit/php-code-coverage/LICENSE
vendored
@@ -1,33 +1,29 @@
|
||||
php-code-coverage
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2009-2022, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
Copyright (c) 2009-2023, Sebastian Bergmann
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Sebastian Bergmann nor the names of his
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues"
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
@@ -32,7 +33,7 @@
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
"sebastian/code-unit-reverse-lookup": "^2.0.2",
|
||||
@@ -46,8 +47,8 @@
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "*",
|
||||
"ext-xdebug": "*"
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
||||
@@ -20,7 +20,6 @@ use function count;
|
||||
use function explode;
|
||||
use function get_class;
|
||||
use function is_array;
|
||||
use function is_file;
|
||||
use function sort;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Runner\PhptTestCase;
|
||||
@@ -77,7 +76,7 @@ final class CodeCoverage
|
||||
private $ignoreDeprecatedCode = false;
|
||||
|
||||
/**
|
||||
* @var PhptTestCase|string|TestCase
|
||||
* @var null|PhptTestCase|string|TestCase
|
||||
*/
|
||||
private $currentId;
|
||||
|
||||
@@ -115,6 +114,11 @@ final class CodeCoverage
|
||||
*/
|
||||
private $cacheDirectory;
|
||||
|
||||
/**
|
||||
* @var ?Directory
|
||||
*/
|
||||
private $cachedReport;
|
||||
|
||||
public function __construct(Driver $driver, Filter $filter)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
@@ -128,7 +132,11 @@ final class CodeCoverage
|
||||
*/
|
||||
public function getReport(): Directory
|
||||
{
|
||||
return (new Builder($this->analyser()))->build($this);
|
||||
if ($this->cachedReport === null) {
|
||||
$this->cachedReport = (new Builder($this->analyser()))->build($this);
|
||||
}
|
||||
|
||||
return $this->cachedReport;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,9 +144,18 @@ final class CodeCoverage
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->currentId = null;
|
||||
$this->data = new ProcessedCodeCoverageData;
|
||||
$this->tests = [];
|
||||
$this->currentId = null;
|
||||
$this->data = new ProcessedCodeCoverageData;
|
||||
$this->tests = [];
|
||||
$this->cachedReport = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function clearCache(): void
|
||||
{
|
||||
$this->cachedReport = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,6 +220,8 @@ final class CodeCoverage
|
||||
$this->currentId = $id;
|
||||
|
||||
$this->driver->start();
|
||||
|
||||
$this->cachedReport = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +240,8 @@ final class CodeCoverage
|
||||
$data = $this->driver->stop();
|
||||
$this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed);
|
||||
|
||||
$this->currentId = null;
|
||||
$this->currentId = null;
|
||||
$this->cachedReport = null;
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -246,6 +266,8 @@ final class CodeCoverage
|
||||
throw new TestIdMissingException;
|
||||
}
|
||||
|
||||
$this->cachedReport = null;
|
||||
|
||||
$this->applyFilter($rawData);
|
||||
|
||||
$this->applyExecutableLinesFilter($rawData);
|
||||
@@ -313,6 +335,8 @@ final class CodeCoverage
|
||||
$this->data->merge($that->data);
|
||||
|
||||
$this->tests = array_merge($this->tests, $that->getTests());
|
||||
|
||||
$this->cachedReport = null;
|
||||
}
|
||||
|
||||
public function enableCheckForUnintentionallyCoveredCode(): void
|
||||
@@ -486,9 +510,16 @@ final class CodeCoverage
|
||||
continue;
|
||||
}
|
||||
|
||||
$linesToBranchMap = $this->analyser()->executableLinesIn($filename);
|
||||
|
||||
$data->keepLineCoverageDataOnlyForLines(
|
||||
$filename,
|
||||
$this->analyser()->executableLinesIn($filename)
|
||||
array_keys($linesToBranchMap)
|
||||
);
|
||||
|
||||
$data->markExecutableLineByBranch(
|
||||
$filename,
|
||||
$linesToBranchMap
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -518,7 +549,7 @@ final class CodeCoverage
|
||||
);
|
||||
|
||||
foreach ($uncoveredFiles as $uncoveredFile) {
|
||||
if (is_file($uncoveredFile)) {
|
||||
if ($this->filter->isFile($uncoveredFile)) {
|
||||
$this->append(
|
||||
RawCodeCoverageData::fromUncoveredFile(
|
||||
$uncoveredFile,
|
||||
@@ -543,7 +574,7 @@ final class CodeCoverage
|
||||
$this->driver->start();
|
||||
|
||||
foreach ($uncoveredFiles as $uncoveredFile) {
|
||||
if (is_file($uncoveredFile)) {
|
||||
if ($this->filter->isFile($uncoveredFile)) {
|
||||
include_once $uncoveredFile;
|
||||
}
|
||||
}
|
||||
@@ -644,7 +675,7 @@ final class CodeCoverage
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new ReflectionException(
|
||||
$e->getMessage(),
|
||||
(int) $e->getCode(),
|
||||
$e->getCode(),
|
||||
$e
|
||||
);
|
||||
}
|
||||
@@ -667,7 +698,9 @@ final class CodeCoverage
|
||||
if ($this->cachesStaticAnalysis()) {
|
||||
$this->analyser = new CachingFileAnalyser(
|
||||
$this->cacheDirectory,
|
||||
$this->analyser
|
||||
$this->analyser,
|
||||
$this->useAnnotationsForIgnoringCode,
|
||||
$this->ignoreDeprecatedCode
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,11 +100,7 @@ final class Filter
|
||||
|
||||
public function isExcluded(string $filename): bool
|
||||
{
|
||||
if (!$this->isFile($filename)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !isset($this->files[$filename]);
|
||||
return !isset($this->files[$filename]) || !$this->isFile($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class AbstractNode implements Countable
|
||||
*/
|
||||
private $id;
|
||||
|
||||
public function __construct(string $name, self $parent = null)
|
||||
public function __construct(string $name, ?self $parent = null)
|
||||
{
|
||||
if (substr($name, -1) === DIRECTORY_SEPARATOR) {
|
||||
$name = substr($name, 0, -1);
|
||||
|
||||
@@ -74,8 +74,6 @@ final class Iterator implements RecursiveIterator
|
||||
|
||||
/**
|
||||
* Returns the sub iterator for the current element.
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
public function getChildren(): self
|
||||
{
|
||||
|
||||
@@ -15,8 +15,12 @@ use function array_flip;
|
||||
use function array_intersect;
|
||||
use function array_intersect_key;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function file_get_contents;
|
||||
use function in_array;
|
||||
use function is_file;
|
||||
use function range;
|
||||
use function trim;
|
||||
use SebastianBergmann\CodeCoverage\Driver\Driver;
|
||||
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
|
||||
|
||||
@@ -87,7 +91,7 @@ final class RawCodeCoverageData
|
||||
{
|
||||
$lineCoverage = [];
|
||||
|
||||
foreach ($analyser->executableLinesIn($filename) as $line) {
|
||||
foreach ($analyser->executableLinesIn($filename) as $line => $branch) {
|
||||
$lineCoverage[$line] = Driver::LINE_NOT_EXECUTED;
|
||||
}
|
||||
|
||||
@@ -137,6 +141,42 @@ final class RawCodeCoverageData
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $linesToBranchMap
|
||||
*/
|
||||
public function markExecutableLineByBranch(string $filename, array $linesToBranchMap): void
|
||||
{
|
||||
if (!isset($this->lineCoverage[$filename])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$linesByBranch = [];
|
||||
|
||||
foreach ($linesToBranchMap as $line => $branch) {
|
||||
$linesByBranch[$branch][] = $line;
|
||||
}
|
||||
|
||||
foreach ($this->lineCoverage[$filename] as $line => $lineStatus) {
|
||||
if (!isset($linesToBranchMap[$line])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$branch = $linesToBranchMap[$line];
|
||||
|
||||
if (!isset($linesByBranch[$branch])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($linesByBranch[$branch] as $lineInBranch) {
|
||||
$this->lineCoverage[$filename][$lineInBranch] = $lineStatus;
|
||||
}
|
||||
|
||||
if (Driver::LINE_EXECUTED === $lineStatus) {
|
||||
unset($linesByBranch[$branch]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $lines
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ use function is_string;
|
||||
use function ksort;
|
||||
use function max;
|
||||
use function range;
|
||||
use function strpos;
|
||||
use function time;
|
||||
use DOMDocument;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
@@ -243,7 +244,9 @@ final class Clover
|
||||
$buffer = $xmlDocument->saveXML();
|
||||
|
||||
if ($target !== null) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
if (!strpos($target, '://') !== false) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
}
|
||||
|
||||
if (@file_put_contents($target, $buffer) === false) {
|
||||
throw new WriteOperationFailedException($target);
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\Report;
|
||||
|
||||
use function basename;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function file_put_contents;
|
||||
use function preg_match;
|
||||
use function range;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
use function time;
|
||||
use DOMImplementation;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
@@ -25,7 +29,7 @@ final class Cobertura
|
||||
/**
|
||||
* @throws WriteOperationFailedException
|
||||
*/
|
||||
public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
|
||||
public function process(CodeCoverage $coverage, ?string $target = null): string
|
||||
{
|
||||
$time = (string) time();
|
||||
|
||||
@@ -84,9 +88,8 @@ final class Cobertura
|
||||
|
||||
$packageElement = $document->createElement('package');
|
||||
$packageComplexity = 0;
|
||||
$packageName = $name ?? '';
|
||||
|
||||
$packageElement->setAttribute('name', $packageName);
|
||||
$packageElement->setAttribute('name', str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()));
|
||||
|
||||
$linesValid = $item->numberOfExecutableLines();
|
||||
$linesCovered = $item->numberOfExecutedLines();
|
||||
@@ -191,7 +194,7 @@ final class Cobertura
|
||||
}
|
||||
}
|
||||
|
||||
if ($report->numberOfFunctions() === 0) {
|
||||
if ($item->numberOfFunctions() === 0) {
|
||||
$packageElement->setAttribute('complexity', (string) $packageComplexity);
|
||||
|
||||
continue;
|
||||
@@ -215,7 +218,7 @@ final class Cobertura
|
||||
|
||||
$classElement->appendChild($classLinesElement);
|
||||
|
||||
$functions = $report->functions();
|
||||
$functions = $item->functions();
|
||||
|
||||
foreach ($functions as $functionName => $function) {
|
||||
if ($function['executableLines'] === 0) {
|
||||
@@ -292,7 +295,9 @@ final class Cobertura
|
||||
$buffer = $document->saveXML();
|
||||
|
||||
if ($target !== null) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
if (!strpos($target, '://') !== false) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
}
|
||||
|
||||
if (@file_put_contents($target, $buffer) === false) {
|
||||
throw new WriteOperationFailedException($target);
|
||||
|
||||
@@ -15,6 +15,7 @@ use function file_put_contents;
|
||||
use function htmlspecialchars;
|
||||
use function is_string;
|
||||
use function round;
|
||||
use function strpos;
|
||||
use DOMDocument;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
|
||||
@@ -124,7 +125,9 @@ final class Crap4j
|
||||
$buffer = $document->saveXML();
|
||||
|
||||
if ($target !== null) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
if (!strpos($target, '://') !== false) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
}
|
||||
|
||||
if (@file_put_contents($target, $buffer) === false) {
|
||||
throw new WriteOperationFailedException($target);
|
||||
|
||||
@@ -80,6 +80,8 @@ use const T_WHILE;
|
||||
use const T_YIELD;
|
||||
use const T_YIELD_FROM;
|
||||
use function array_key_exists;
|
||||
use function array_keys;
|
||||
use function array_merge;
|
||||
use function array_pop;
|
||||
use function array_unique;
|
||||
use function constant;
|
||||
@@ -89,6 +91,9 @@ use function explode;
|
||||
use function file_get_contents;
|
||||
use function htmlspecialchars;
|
||||
use function is_string;
|
||||
use function ksort;
|
||||
use function range;
|
||||
use function sort;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
@@ -129,7 +134,7 @@ final class File extends Renderer
|
||||
[
|
||||
'items' => $this->renderItems($node),
|
||||
'lines' => $this->renderSourceWithLineCoverage($node),
|
||||
'legend' => '<p><span class="success"><strong>Executed</strong></span><span class="danger"><strong>Not Executed</strong></span><span class="warning"><strong>Dead Code</strong></span></p>',
|
||||
'legend' => '<p><span class="legend covered-by-small-tests">Covered by small (and larger) tests</span><span class="legend covered-by-medium-tests">Covered by medium (and large) tests</span><span class="legend covered-by-large-tests">Covered by large tests (and tests of unknown size)</span><span class="legend not-covered">Not covered</span><span class="legend not-coverable">Not coverable</span></p>',
|
||||
'structure' => '',
|
||||
]
|
||||
);
|
||||
@@ -797,8 +802,15 @@ final class File extends Renderer
|
||||
$singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}');
|
||||
|
||||
$lines = '';
|
||||
$first = true;
|
||||
|
||||
foreach ($path['path'] as $branchId) {
|
||||
if ($first) {
|
||||
$first = false;
|
||||
} else {
|
||||
$lines .= ' <tr><td colspan="2"> </td></tr>' . "\n";
|
||||
}
|
||||
|
||||
$branchLines = range($branches[$branchId]['line_start'], $branches[$branchId]['line_end']);
|
||||
sort($branchLines); // sometimes end_line < start_line
|
||||
|
||||
@@ -834,6 +846,7 @@ final class File extends Renderer
|
||||
|
||||
$popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]);
|
||||
}
|
||||
|
||||
$trClass = $lineCss . ' popin';
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,9 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
font-kerning: normal;
|
||||
font-variant-ligatures: common-ligatures;
|
||||
text-rendering: optimizeLegibility;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
@@ -8,6 +13,8 @@ body {
|
||||
|
||||
.octicon {
|
||||
margin-right:.25em;
|
||||
vertical-align: baseline;
|
||||
width: 0.75em;
|
||||
}
|
||||
|
||||
.table-bordered>thead>tr>td {
|
||||
@@ -57,6 +64,7 @@ body {
|
||||
}
|
||||
|
||||
td.big {
|
||||
vertical-align: middle;
|
||||
width: 117px;
|
||||
}
|
||||
|
||||
@@ -112,7 +120,7 @@ svg text {
|
||||
|
||||
.scrollbox {
|
||||
height:245px;
|
||||
overflow-x:hidden;
|
||||
overflow-x:scroll;
|
||||
overflow-y:scroll;
|
||||
}
|
||||
|
||||
@@ -120,3 +128,31 @@ table + .structure-heading {
|
||||
border-top: 1px solid lightgrey;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.legend {
|
||||
font-weight: bold;
|
||||
margin-right: 2px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.covered-by-small-tests {
|
||||
background-color: #99cb84;
|
||||
}
|
||||
|
||||
.covered-by-medium-tests {
|
||||
background-color: #c3e3b5;
|
||||
}
|
||||
|
||||
.covered-by-large-tests {
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
|
||||
.not-covered {
|
||||
background-color: #f2dede;
|
||||
}
|
||||
|
||||
.not-coverable {
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Dashboard for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/nv.d3.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/nv.d3.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -137,9 +137,9 @@
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/d3.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/nv.d3.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/d3.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/nv.d3.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
nv.addGraph(function() {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Dashboard for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/nv.d3.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/nv.d3.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -137,9 +137,9 @@
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/d3.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/nv.d3.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/d3.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/nv.d3.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
nv.addGraph(function() {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Code Coverage for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Code Coverage for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Code Coverage for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -57,9 +57,9 @@
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/popper.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/file.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/popper.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/bootstrap.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/file.js?v={{version}}" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Code Coverage for {{full_path}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
|
||||
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
@@ -59,9 +59,9 @@
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/popper.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/file.js" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/popper.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/bootstrap.min.js?v={{version}}" type="text/javascript"></script>
|
||||
<script src="{{path_to_root}}_js/file.js?v={{version}}" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<tr>
|
||||
<td class="{{classes_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}} big">{{lines_bar}}</td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<tr>
|
||||
<td class="{{classes_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}} big">{{lines_bar}}</td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<tr>
|
||||
<td class="{{methods_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}} big">{{lines_bar}}</td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<tr>
|
||||
<td class="{{methods_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}}">{{name}}</td>
|
||||
<td class="{{lines_level}} big">{{lines_bar}}</td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
|
||||
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report;
|
||||
use function dirname;
|
||||
use function file_put_contents;
|
||||
use function serialize;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use SebastianBergmann\CodeCoverage\CodeCoverage;
|
||||
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
|
||||
use SebastianBergmann\CodeCoverage\Util\Filesystem;
|
||||
@@ -21,17 +21,15 @@ final class PHP
|
||||
{
|
||||
public function process(CodeCoverage $coverage, ?string $target = null): string
|
||||
{
|
||||
$buffer = sprintf(
|
||||
"<?php
|
||||
return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'%s%s%sEND_OF_COVERAGE_SERIALIZATION%s);",
|
||||
PHP_EOL,
|
||||
serialize($coverage),
|
||||
PHP_EOL,
|
||||
PHP_EOL
|
||||
);
|
||||
$coverage->clearCache();
|
||||
|
||||
$buffer = "<?php
|
||||
return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'" . PHP_EOL . serialize($coverage) . PHP_EOL . 'END_OF_COVERAGE_SERIALIZATION' . PHP_EOL . ');';
|
||||
|
||||
if ($target !== null) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
if (!strpos($target, '://') !== false) {
|
||||
Filesystem::createDirectory(dirname($target));
|
||||
}
|
||||
|
||||
if (@file_put_contents($target, $buffer) === false) {
|
||||
throw new WriteOperationFailedException($target);
|
||||
|
||||
@@ -37,7 +37,7 @@ final class Coverage
|
||||
{
|
||||
$this->contextNode = $context;
|
||||
|
||||
$this->writer = new XMLWriter();
|
||||
$this->writer = new XMLWriter;
|
||||
$this->writer->openMemory();
|
||||
$this->writer->startElementNS(null, $context->nodeName, 'https://schema.phpunit.de/coverage/1.0');
|
||||
$this->writer->writeAttribute('nr', $line);
|
||||
|
||||
@@ -20,7 +20,7 @@ final class Report extends File
|
||||
{
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$dom = new DOMDocument();
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><file /></phpunit>');
|
||||
|
||||
$contextNode = $dom->getElementsByTagNameNS(
|
||||
|
||||
@@ -31,7 +31,7 @@ final class Source
|
||||
{
|
||||
$context = $this->context;
|
||||
|
||||
$tokens = (new Tokenizer())->parse($source);
|
||||
$tokens = (new Tokenizer)->parse($source);
|
||||
$srcDom = (new XMLSerializer(new NamespaceUri($context->namespaceURI)))->toDom($tokens);
|
||||
|
||||
$context->parentNode->replaceChild(
|
||||
|
||||
@@ -17,7 +17,6 @@ use DOMElement;
|
||||
final class Tests
|
||||
{
|
||||
private $contextNode;
|
||||
|
||||
private $codeMap = [
|
||||
-1 => 'UNKNOWN', // PHPUnit_Runner_BaseTestRunner::STATUS_UNKNOWN
|
||||
0 => 'PASSED', // PHPUnit_Runner_BaseTestRunner::STATUS_PASSED
|
||||
|
||||
@@ -20,7 +20,9 @@ final class CacheWarmer
|
||||
new ParsingFileAnalyser(
|
||||
$useAnnotationsForIgnoringCode,
|
||||
$ignoreDeprecatedCode
|
||||
)
|
||||
),
|
||||
$useAnnotationsForIgnoringCode,
|
||||
$ignoreDeprecatedCode,
|
||||
);
|
||||
|
||||
foreach ($filter->files() as $file) {
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
use function assert;
|
||||
use function crc32;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function implode;
|
||||
use function is_file;
|
||||
use function md5;
|
||||
use function serialize;
|
||||
use GlobIterator;
|
||||
use function unserialize;
|
||||
use SebastianBergmann\CodeCoverage\Util\Filesystem;
|
||||
use SplFileInfo;
|
||||
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
|
||||
|
||||
/**
|
||||
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
|
||||
@@ -29,31 +29,39 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
*/
|
||||
private static $cacheVersion;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $directory;
|
||||
|
||||
/**
|
||||
* @var FileAnalyser
|
||||
*/
|
||||
private $analyser;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $useAnnotationsForIgnoringCode;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $ignoreDeprecatedCode;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $cache = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $directory;
|
||||
|
||||
public function __construct(string $directory, FileAnalyser $analyser)
|
||||
public function __construct(string $directory, FileAnalyser $analyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
|
||||
{
|
||||
Filesystem::createDirectory($directory);
|
||||
|
||||
$this->analyser = $analyser;
|
||||
$this->directory = $directory;
|
||||
|
||||
if (self::$cacheVersion === null) {
|
||||
$this->calculateCacheVersion();
|
||||
}
|
||||
$this->analyser = $analyser;
|
||||
$this->directory = $directory;
|
||||
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
|
||||
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
|
||||
}
|
||||
|
||||
public function classesIn(string $filename): array
|
||||
@@ -165,19 +173,37 @@ final class CachingFileAnalyser implements FileAnalyser
|
||||
|
||||
private function cacheFile(string $filename): string
|
||||
{
|
||||
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . crc32(file_get_contents($filename)) . self::$cacheVersion);
|
||||
$cacheKey = md5(
|
||||
implode(
|
||||
"\0",
|
||||
[
|
||||
$filename,
|
||||
file_get_contents($filename),
|
||||
self::cacheVersion(),
|
||||
$this->useAnnotationsForIgnoringCode,
|
||||
$this->ignoreDeprecatedCode,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
return $this->directory . DIRECTORY_SEPARATOR . $cacheKey;
|
||||
}
|
||||
|
||||
private function calculateCacheVersion(): void
|
||||
private static function cacheVersion(): string
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
foreach (new GlobIterator(__DIR__ . '/*.php') as $file) {
|
||||
assert($file instanceof SplFileInfo);
|
||||
|
||||
$buffer .= file_get_contents($file->getPathname());
|
||||
if (self::$cacheVersion !== null) {
|
||||
return self::$cacheVersion;
|
||||
}
|
||||
|
||||
self::$cacheVersion = (string) crc32($buffer);
|
||||
$buffer = [];
|
||||
|
||||
foreach ((new FileIteratorFacade)->getFilesAsArray(__DIR__, '.php') as $file) {
|
||||
$buffer[] = $file;
|
||||
$buffer[] = file_get_contents($file);
|
||||
}
|
||||
|
||||
self::$cacheVersion = md5(implode("\0", $buffer));
|
||||
|
||||
return self::$cacheVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
use function assert;
|
||||
use function implode;
|
||||
use function rtrim;
|
||||
use function trim;
|
||||
@@ -25,6 +26,7 @@ use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\UnionType;
|
||||
use PhpParser\NodeAbstract;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor;
|
||||
@@ -179,8 +181,12 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
return '?' . $type->type;
|
||||
}
|
||||
|
||||
if ($type instanceof UnionType || $type instanceof IntersectionType) {
|
||||
return $this->unionOrIntersectionAsString($type);
|
||||
if ($type instanceof UnionType) {
|
||||
return $this->unionTypeAsString($type);
|
||||
}
|
||||
|
||||
if ($type instanceof IntersectionType) {
|
||||
return $this->intersectionTypeAsString($type);
|
||||
}
|
||||
|
||||
return $type->toString();
|
||||
@@ -297,27 +303,43 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
|
||||
return trim(rtrim($namespacedName, $name), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param UnionType|IntersectionType $type
|
||||
*/
|
||||
private function unionOrIntersectionAsString(ComplexType $type): string
|
||||
private function unionTypeAsString(UnionType $node): string
|
||||
{
|
||||
if ($type instanceof UnionType) {
|
||||
$separator = '|';
|
||||
} else {
|
||||
$separator = '&';
|
||||
}
|
||||
|
||||
$types = [];
|
||||
|
||||
foreach ($type->types as $_type) {
|
||||
if ($_type instanceof Name) {
|
||||
$types[] = $_type->toCodeString();
|
||||
} else {
|
||||
$types[] = $_type->toString();
|
||||
foreach ($node->types as $type) {
|
||||
if ($type instanceof IntersectionType) {
|
||||
$types[] = '(' . $this->intersectionTypeAsString($type) . ')';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$types[] = $this->typeAsString($type);
|
||||
}
|
||||
|
||||
return implode($separator, $types);
|
||||
return implode('|', $types);
|
||||
}
|
||||
|
||||
private function intersectionTypeAsString(IntersectionType $node): string
|
||||
{
|
||||
$types = [];
|
||||
|
||||
foreach ($node->types as $type) {
|
||||
$types[] = $this->typeAsString($type);
|
||||
}
|
||||
|
||||
return implode('&', $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param Identifier|Name $node $node
|
||||
*/
|
||||
private function typeAsString(NodeAbstract $node): string
|
||||
{
|
||||
if ($node instanceof Name) {
|
||||
return $node->toCodeString();
|
||||
}
|
||||
|
||||
return $node->toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,46 +9,19 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
use function array_diff_key;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function current;
|
||||
use function end;
|
||||
use function explode;
|
||||
use function max;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function range;
|
||||
use function reset;
|
||||
use function sprintf;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
use PhpParser\Node\Expr\CallLike;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\Match_;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\NullsafePropertyFetch;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\MatchArm;
|
||||
use PhpParser\Node\Scalar\Encapsed;
|
||||
use PhpParser\Node\Stmt\Break_;
|
||||
use PhpParser\Node\Stmt\Case_;
|
||||
use PhpParser\Node\Stmt\Catch_;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Continue_;
|
||||
use PhpParser\Node\Stmt\Do_;
|
||||
use PhpParser\Node\Stmt\Echo_;
|
||||
use PhpParser\Node\Stmt\Else_;
|
||||
use PhpParser\Node\Stmt\ElseIf_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Finally_;
|
||||
use PhpParser\Node\Stmt\For_;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\Goto_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Switch_;
|
||||
use PhpParser\Node\Stmt\Throw_;
|
||||
use PhpParser\Node\Stmt\TryCatch;
|
||||
use PhpParser\Node\Stmt\Unset_;
|
||||
use PhpParser\Node\Stmt\While_;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
|
||||
/**
|
||||
@@ -57,217 +30,361 @@ use PhpParser\NodeVisitorAbstract;
|
||||
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
/**
|
||||
* @psalm-var array<int, int>
|
||||
* @var int
|
||||
*/
|
||||
private $executableLines = [];
|
||||
private $nextBranch = 0;
|
||||
|
||||
/**
|
||||
* @psalm-var array<int, int>
|
||||
* @var string
|
||||
*/
|
||||
private $propertyLines = [];
|
||||
private $source;
|
||||
|
||||
/**
|
||||
* @psalm-var array<int, Return_>
|
||||
* @var array<int, int>
|
||||
*/
|
||||
private $returns = [];
|
||||
private $executableLinesGroupedByBranch = [];
|
||||
|
||||
/**
|
||||
* @var array<int, bool>
|
||||
*/
|
||||
private $unsets = [];
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
private $commentsToCheckForUnset = [];
|
||||
|
||||
public function __construct(string $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node): void
|
||||
{
|
||||
$this->savePropertyLines($node);
|
||||
foreach ($node->getComments() as $comment) {
|
||||
$commentLine = $comment->getStartLine();
|
||||
|
||||
if (!isset($this->executableLinesGroupedByBranch[$commentLine])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (explode("\n", $comment->getText()) as $text) {
|
||||
$this->commentsToCheckForUnset[$commentLine] = $text;
|
||||
$commentLine++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Scalar\String_ ||
|
||||
$node instanceof Node\Scalar\EncapsedStringPart) {
|
||||
$startLine = $node->getStartLine() + 1;
|
||||
$endLine = $node->getEndLine() - 1;
|
||||
|
||||
if ($startLine <= $endLine) {
|
||||
foreach (range($startLine, $endLine) as $line) {
|
||||
unset($this->executableLinesGroupedByBranch[$line]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->isExecutable($node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->getLines($node) as $line) {
|
||||
if (isset($this->propertyLines[$line])) {
|
||||
if ($node instanceof Node\Stmt\Interface_) {
|
||||
foreach (range($node->getStartLine(), $node->getEndLine()) as $line) {
|
||||
$this->unsets[$line] = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Declare_ ||
|
||||
$node instanceof Node\Stmt\DeclareDeclare ||
|
||||
$node instanceof Node\Stmt\Else_ ||
|
||||
$node instanceof Node\Stmt\EnumCase ||
|
||||
$node instanceof Node\Stmt\Finally_ ||
|
||||
$node instanceof Node\Stmt\GroupUse ||
|
||||
$node instanceof Node\Stmt\Label ||
|
||||
$node instanceof Node\Stmt\Namespace_ ||
|
||||
$node instanceof Node\Stmt\Nop ||
|
||||
$node instanceof Node\Stmt\Switch_ ||
|
||||
$node instanceof Node\Stmt\TryCatch ||
|
||||
$node instanceof Node\Stmt\Use_ ||
|
||||
$node instanceof Node\Stmt\UseUse ||
|
||||
$node instanceof Node\Expr\ConstFetch ||
|
||||
$node instanceof Node\Expr\Match_ ||
|
||||
$node instanceof Node\Expr\Variable ||
|
||||
$node instanceof Node\Expr\Throw_ ||
|
||||
$node instanceof Node\ComplexType ||
|
||||
$node instanceof Node\Const_ ||
|
||||
$node instanceof Node\Identifier ||
|
||||
$node instanceof Node\Name ||
|
||||
$node instanceof Node\Param ||
|
||||
$node instanceof Node\Scalar) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* nikic/php-parser ^4.18 represents <code>throw</code> statements
|
||||
* as <code>Stmt\Throw_</code> objects
|
||||
*/
|
||||
if ($node instanceof Node\Stmt\Throw_) {
|
||||
$this->setLineBranch($node->expr->getEndLine(), $node->expr->getEndLine(), ++$this->nextBranch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* nikic/php-parser ^5 represents <code>throw</code> statements
|
||||
* as <code>Stmt\Expression</code> objects that contain an
|
||||
* <code>Expr\Throw_</code> object
|
||||
*/
|
||||
if ($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Throw_) {
|
||||
$this->setLineBranch($node->expr->expr->getEndLine(), $node->expr->expr->getEndLine(), ++$this->nextBranch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Enum_ ||
|
||||
$node instanceof Node\Stmt\Function_ ||
|
||||
$node instanceof Node\Stmt\Class_ ||
|
||||
$node instanceof Node\Stmt\ClassMethod ||
|
||||
$node instanceof Node\Expr\Closure ||
|
||||
$node instanceof Node\Stmt\Trait_) {
|
||||
$isConcreteClassLike = $node instanceof Node\Stmt\Enum_ || $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_;
|
||||
|
||||
if (null !== $node->stmts) {
|
||||
foreach ($node->stmts as $stmt) {
|
||||
if ($stmt instanceof Node\Stmt\Nop) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (range($stmt->getStartLine(), $stmt->getEndLine()) as $line) {
|
||||
unset($this->executableLinesGroupedByBranch[$line]);
|
||||
|
||||
if (
|
||||
$isConcreteClassLike &&
|
||||
!$stmt instanceof Node\Stmt\ClassMethod
|
||||
) {
|
||||
$this->unsets[$line] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isConcreteClassLike) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->executableLines[$line] = $line;
|
||||
}
|
||||
}
|
||||
$hasEmptyBody = [] === $node->stmts ||
|
||||
null === $node->stmts ||
|
||||
(
|
||||
1 === count($node->stmts) &&
|
||||
$node->stmts[0] instanceof Node\Stmt\Nop
|
||||
);
|
||||
|
||||
/**
|
||||
* @psalm-return array<int, int>
|
||||
*/
|
||||
public function executableLines(): array
|
||||
{
|
||||
$this->computeReturns();
|
||||
if ($hasEmptyBody) {
|
||||
if ($node->getEndLine() === $node->getStartLine()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sort($this->executableLines);
|
||||
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
|
||||
return $this->executableLines;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private function savePropertyLines(Node $node): void
|
||||
{
|
||||
if (!$node instanceof Property && !$node instanceof Node\Stmt\ClassConst) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (range($node->getStartLine(), $node->getEndLine()) as $index) {
|
||||
$this->propertyLines[$index] = $index;
|
||||
}
|
||||
}
|
||||
if ($node instanceof Node\Expr\ArrowFunction) {
|
||||
$startLine = max(
|
||||
$node->getStartLine() + 1,
|
||||
$node->expr->getStartLine()
|
||||
);
|
||||
|
||||
private function computeReturns(): void
|
||||
{
|
||||
foreach ($this->returns as $return) {
|
||||
foreach (range($return->getStartLine(), $return->getEndLine()) as $loc) {
|
||||
if (isset($this->executableLines[$loc])) {
|
||||
continue 2;
|
||||
$endLine = $node->expr->getEndLine();
|
||||
|
||||
if ($endLine < $startLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch($startLine, $endLine, ++$this->nextBranch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\Ternary) {
|
||||
if (null !== $node->if &&
|
||||
$node->getStartLine() !== $node->if->getEndLine()) {
|
||||
$this->setLineBranch($node->if->getStartLine(), $node->if->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
if ($node->getStartLine() !== $node->else->getEndLine()) {
|
||||
$this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\BinaryOp\Coalesce) {
|
||||
if ($node->getStartLine() !== $node->getEndLine()) {
|
||||
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\If_ ||
|
||||
$node instanceof Node\Stmt\ElseIf_ ||
|
||||
$node instanceof Node\Stmt\Case_) {
|
||||
if (null === $node->cond) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setLineBranch(
|
||||
$node->cond->getStartLine(),
|
||||
$node->cond->getStartLine(),
|
||||
++$this->nextBranch
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\For_) {
|
||||
$startLine = null;
|
||||
$endLine = null;
|
||||
|
||||
if ([] !== $node->init) {
|
||||
$startLine = $node->init[0]->getStartLine();
|
||||
|
||||
end($node->init);
|
||||
|
||||
$endLine = current($node->init)->getEndLine();
|
||||
|
||||
reset($node->init);
|
||||
}
|
||||
|
||||
if ([] !== $node->cond) {
|
||||
if (null === $startLine) {
|
||||
$startLine = $node->cond[0]->getStartLine();
|
||||
}
|
||||
|
||||
end($node->cond);
|
||||
|
||||
$endLine = current($node->cond)->getEndLine();
|
||||
|
||||
reset($node->cond);
|
||||
}
|
||||
|
||||
$line = $return->getEndLine();
|
||||
|
||||
if ($return->expr !== null) {
|
||||
$line = $return->expr->getStartLine();
|
||||
}
|
||||
|
||||
$this->executableLines[$line] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
private function getLines(Node $node): array
|
||||
{
|
||||
if ($node instanceof Cast ||
|
||||
$node instanceof PropertyFetch ||
|
||||
$node instanceof NullsafePropertyFetch ||
|
||||
$node instanceof StaticPropertyFetch) {
|
||||
return [$node->getEndLine()];
|
||||
}
|
||||
|
||||
if ($node instanceof ArrayDimFetch) {
|
||||
if (null === $node->dim) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [$node->dim->getStartLine()];
|
||||
}
|
||||
|
||||
if ($node instanceof Array_) {
|
||||
$startLine = $node->getStartLine();
|
||||
|
||||
if (isset($this->executableLines[$startLine])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ([] === $node->items) {
|
||||
return [$node->getEndLine()];
|
||||
}
|
||||
|
||||
if ($node->items[0] instanceof ArrayItem) {
|
||||
return [$node->items[0]->getStartLine()];
|
||||
}
|
||||
}
|
||||
|
||||
if ($node instanceof ClassMethod) {
|
||||
if ($node->name->name !== '__construct') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$existsAPromotedProperty = false;
|
||||
|
||||
foreach ($node->getParams() as $param) {
|
||||
if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) {
|
||||
$existsAPromotedProperty = true;
|
||||
|
||||
break;
|
||||
if ([] !== $node->loop) {
|
||||
if (null === $startLine) {
|
||||
$startLine = $node->loop[0]->getStartLine();
|
||||
}
|
||||
|
||||
end($node->loop);
|
||||
|
||||
$endLine = current($node->loop)->getEndLine();
|
||||
|
||||
reset($node->loop);
|
||||
}
|
||||
|
||||
if ($existsAPromotedProperty) {
|
||||
// Only the line with `function` keyword should be listed here
|
||||
// but `nikic/php-parser` doesn't provide a way to fetch it
|
||||
return range($node->getStartLine(), $node->name->getEndLine());
|
||||
if (null === $startLine || null === $endLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
return [];
|
||||
$this->setLineBranch(
|
||||
$startLine,
|
||||
$endLine,
|
||||
++$this->nextBranch
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof MethodCall) {
|
||||
return [$node->name->getStartLine()];
|
||||
if ($node instanceof Node\Stmt\Foreach_) {
|
||||
$this->setLineBranch(
|
||||
$node->expr->getStartLine(),
|
||||
$node->valueVar->getEndLine(),
|
||||
++$this->nextBranch
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Ternary) {
|
||||
$lines = [$node->cond->getStartLine()];
|
||||
if ($node instanceof Node\Stmt\While_ ||
|
||||
$node instanceof Node\Stmt\Do_) {
|
||||
$this->setLineBranch(
|
||||
$node->cond->getStartLine(),
|
||||
$node->cond->getEndLine(),
|
||||
++$this->nextBranch
|
||||
);
|
||||
|
||||
if (null !== $node->if) {
|
||||
$lines[] = $node->if->getStartLine();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Stmt\Catch_) {
|
||||
assert([] !== $node->types);
|
||||
$startLine = $node->types[0]->getStartLine();
|
||||
end($node->types);
|
||||
$endLine = current($node->types)->getEndLine();
|
||||
|
||||
$this->setLineBranch(
|
||||
$startLine,
|
||||
$endLine,
|
||||
++$this->nextBranch
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Expr\CallLike) {
|
||||
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
|
||||
$branch = $this->executableLinesGroupedByBranch[$node->getStartLine()];
|
||||
} else {
|
||||
$branch = ++$this->nextBranch;
|
||||
}
|
||||
|
||||
$lines[] = $node->else->getStartLine();
|
||||
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch);
|
||||
|
||||
return $lines;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Match_) {
|
||||
return [$node->cond->getStartLine()];
|
||||
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof MatchArm) {
|
||||
return [$node->body->getStartLine()];
|
||||
}
|
||||
|
||||
if ($node instanceof Expression && (
|
||||
$node->expr instanceof Cast ||
|
||||
$node->expr instanceof Match_ ||
|
||||
$node->expr instanceof MethodCall
|
||||
)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($node instanceof Return_) {
|
||||
$this->returns[] = $node;
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return [$node->getStartLine()];
|
||||
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch);
|
||||
}
|
||||
|
||||
private function isExecutable(Node $node): bool
|
||||
public function afterTraverse(array $nodes): void
|
||||
{
|
||||
return $node instanceof Assign ||
|
||||
$node instanceof ArrayDimFetch ||
|
||||
$node instanceof Array_ ||
|
||||
$node instanceof BinaryOp ||
|
||||
$node instanceof Break_ ||
|
||||
$node instanceof CallLike ||
|
||||
$node instanceof Case_ ||
|
||||
$node instanceof Cast ||
|
||||
$node instanceof Catch_ ||
|
||||
$node instanceof ClassMethod ||
|
||||
$node instanceof Closure ||
|
||||
$node instanceof Continue_ ||
|
||||
$node instanceof Do_ ||
|
||||
$node instanceof Echo_ ||
|
||||
$node instanceof ElseIf_ ||
|
||||
$node instanceof Else_ ||
|
||||
$node instanceof Encapsed ||
|
||||
$node instanceof Expression ||
|
||||
$node instanceof Finally_ ||
|
||||
$node instanceof For_ ||
|
||||
$node instanceof Foreach_ ||
|
||||
$node instanceof Goto_ ||
|
||||
$node instanceof If_ ||
|
||||
$node instanceof Match_ ||
|
||||
$node instanceof MatchArm ||
|
||||
$node instanceof MethodCall ||
|
||||
$node instanceof NullsafePropertyFetch ||
|
||||
$node instanceof PropertyFetch ||
|
||||
$node instanceof Return_ ||
|
||||
$node instanceof StaticPropertyFetch ||
|
||||
$node instanceof Switch_ ||
|
||||
$node instanceof Ternary ||
|
||||
$node instanceof Throw_ ||
|
||||
$node instanceof TryCatch ||
|
||||
$node instanceof Unset_ ||
|
||||
$node instanceof While_;
|
||||
$lines = explode("\n", $this->source);
|
||||
|
||||
foreach ($lines as $lineNumber => $line) {
|
||||
$lineNumber++;
|
||||
|
||||
if (1 === preg_match('/^\s*$/', $line) ||
|
||||
(
|
||||
isset($this->commentsToCheckForUnset[$lineNumber]) &&
|
||||
1 === preg_match(sprintf('/^\s*%s\s*$/', preg_quote($this->commentsToCheckForUnset[$lineNumber], '/')), $line)
|
||||
)) {
|
||||
unset($this->executableLinesGroupedByBranch[$lineNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->executableLinesGroupedByBranch = array_diff_key(
|
||||
$this->executableLinesGroupedByBranch,
|
||||
$this->unsets
|
||||
);
|
||||
}
|
||||
|
||||
public function executableLinesGroupedByBranch(): array
|
||||
{
|
||||
return $this->executableLinesGroupedByBranch;
|
||||
}
|
||||
|
||||
private function setLineBranch(int $start, int $end, int $branch): void
|
||||
{
|
||||
foreach (range($start, $end) as $line) {
|
||||
$this->executableLinesGroupedByBranch[$line] = $branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
use function array_merge;
|
||||
use function assert;
|
||||
use function range;
|
||||
use function strpos;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Attribute;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
@@ -52,7 +54,8 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
!$node instanceof Trait_ &&
|
||||
!$node instanceof Interface_ &&
|
||||
!$node instanceof ClassMethod &&
|
||||
!$node instanceof Function_) {
|
||||
!$node instanceof Function_ &&
|
||||
!$node instanceof Attribute) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,11 +63,16 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
return;
|
||||
}
|
||||
|
||||
// Workaround for https://bugs.xdebug.org/view.php?id=1798
|
||||
if ($node instanceof Class_ ||
|
||||
$node instanceof Trait_ ||
|
||||
$node instanceof Interface_) {
|
||||
$node instanceof Interface_ ||
|
||||
$node instanceof Attribute) {
|
||||
$this->ignoredLines[] = $node->getStartLine();
|
||||
|
||||
assert($node->name !== null);
|
||||
|
||||
// Workaround for https://github.com/nikic/PHP-Parser/issues/886
|
||||
$this->ignoredLines[] = $node->name->getStartLine();
|
||||
}
|
||||
|
||||
if (!$this->useAnnotationsForIgnoringCode) {
|
||||
@@ -75,6 +83,19 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processDocComment($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return list<int>
|
||||
*/
|
||||
public function ignoredLines(): array
|
||||
{
|
||||
return $this->ignoredLines;
|
||||
}
|
||||
|
||||
private function processDocComment(Node $node): void
|
||||
{
|
||||
$docComment = $node->getDocComment();
|
||||
|
||||
if ($docComment === null) {
|
||||
@@ -95,12 +116,4 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return list<int>
|
||||
*/
|
||||
public function ignoredLines(): array
|
||||
{
|
||||
return $this->ignoredLines;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,19 @@
|
||||
*/
|
||||
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
|
||||
|
||||
use function array_merge;
|
||||
use function array_unique;
|
||||
use function assert;
|
||||
use function file_get_contents;
|
||||
use function is_array;
|
||||
use function max;
|
||||
use function range;
|
||||
use function sort;
|
||||
use function sprintf;
|
||||
use function substr_count;
|
||||
use function token_get_all;
|
||||
use function trim;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Lexer;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor\NameResolver;
|
||||
use PhpParser\NodeVisitor\ParentConnectingVisitor;
|
||||
@@ -139,10 +141,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
$linesOfCode = 1;
|
||||
}
|
||||
|
||||
$parser = (new ParserFactory)->create(
|
||||
ParserFactory::PREFER_PHP7,
|
||||
new Lexer
|
||||
);
|
||||
$parser = (new ParserFactory)->createForHostVersion();
|
||||
|
||||
try {
|
||||
$nodes = $parser->parse($source);
|
||||
@@ -153,7 +152,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
|
||||
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
|
||||
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
|
||||
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor;
|
||||
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($source);
|
||||
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
$traverser->addVisitor(new ParentConnectingVisitor);
|
||||
@@ -172,7 +171,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
$filename,
|
||||
$error->getMessage()
|
||||
),
|
||||
(int) $error->getCode(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
);
|
||||
}
|
||||
@@ -181,7 +180,7 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
|
||||
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
|
||||
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
|
||||
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLines();
|
||||
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLinesGroupedByBranch();
|
||||
$this->ignoredLines[$filename] = [];
|
||||
|
||||
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
|
||||
@@ -206,45 +205,44 @@ final class ParsingFileAnalyser implements FileAnalyser
|
||||
|
||||
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void
|
||||
{
|
||||
$ignore = false;
|
||||
$stop = false;
|
||||
if (!$useAnnotationsForIgnoringCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$start = false;
|
||||
|
||||
foreach (token_get_all($source) as $token) {
|
||||
if (!is_array($token)) {
|
||||
if (!is_array($token) ||
|
||||
!(T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($token[0]) {
|
||||
case T_COMMENT:
|
||||
case T_DOC_COMMENT:
|
||||
if (!$useAnnotationsForIgnoringCode) {
|
||||
break;
|
||||
}
|
||||
$comment = trim($token[1]);
|
||||
|
||||
$comment = trim($token[1]);
|
||||
|
||||
if ($comment === '// @codeCoverageIgnore' ||
|
||||
$comment === '//@codeCoverageIgnore') {
|
||||
$ignore = true;
|
||||
$stop = true;
|
||||
} elseif ($comment === '// @codeCoverageIgnoreStart' ||
|
||||
$comment === '//@codeCoverageIgnoreStart') {
|
||||
$ignore = true;
|
||||
} elseif ($comment === '// @codeCoverageIgnoreEnd' ||
|
||||
$comment === '//@codeCoverageIgnoreEnd') {
|
||||
$stop = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($ignore) {
|
||||
if ($comment === '// @codeCoverageIgnore' ||
|
||||
$comment === '//@codeCoverageIgnore') {
|
||||
$this->ignoredLines[$filename][] = $token[2];
|
||||
|
||||
if ($stop) {
|
||||
$ignore = false;
|
||||
$stop = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comment === '// @codeCoverageIgnoreStart' ||
|
||||
$comment === '//@codeCoverageIgnoreStart') {
|
||||
$start = $token[2];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($comment === '// @codeCoverageIgnoreEnd' ||
|
||||
$comment === '//@codeCoverageIgnoreEnd') {
|
||||
if (false === $start) {
|
||||
$start = $token[2];
|
||||
}
|
||||
|
||||
$this->ignoredLines[$filename] = array_merge(
|
||||
$this->ignoredLines[$filename],
|
||||
range($start, $token[2])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ final class Version
|
||||
public static function id(): string
|
||||
{
|
||||
if (self::$version === null) {
|
||||
self::$version = (new VersionId('9.2.15', dirname(__DIR__)))->getVersion();
|
||||
self::$version = (new VersionId('9.2.31', dirname(__DIR__)))->getVersion();
|
||||
}
|
||||
|
||||
return self::$version;
|
||||
|
||||
Reference in New Issue
Block a user