diff --git a/app/composer-dependency-analyser.php b/app/composer-dependency-analyser.php
index 817c82607..e4d584303 100644
--- a/app/composer-dependency-analyser.php
+++ b/app/composer-dependency-analyser.php
@@ -6,6 +6,9 @@
use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;
return (new Configuration())
+ ->setFileExtensions(['php', 'phpt'])
+ ->addPathToScan(__DIR__ . '/tests', true)
+
// Add classes from services.neon and extensions.neon
->addForceUsedSymbols(DiServices::getAllClasses())
@@ -15,6 +18,14 @@
// It's used, believe me
->ignoreErrorsOnPackage('latte/latte', [ErrorType::UNUSED_DEPENDENCY])
+ ->ignoreErrorsOnExtensions([
+ 'ext-gd', // Used by e.g. Nette\Http\FileUpload::toImage which is used by MichalSpacekCz\Media\VideoThumbnails::validateUpload()
+ 'ext-pcntl', // Used by latte/latte Latte\Tools\Linter and nette/tester's Tester\Runner\CliTester
+ ], [ErrorType::UNUSED_DEPENDENCY])
+
+ // shipmonk/composer-dependency-analyser#203
+ ->ignoreErrorsOnExtensionAndPath('ext-session', 'src/EasterEgg/PhpInfoCookieSanitization.php', [ErrorType::SHADOW_DEPENDENCY])
+
// TestCaseRunner is used only in tests
->ignoreErrorsOnPackageAndPath('nette/tester', __DIR__ . '/src/Test/TestCaseRunner.php', [ErrorType::DEV_DEPENDENCY_IN_PROD])
;
diff --git a/app/composer.json b/app/composer.json
index a4f323e3a..f2ece6a1f 100644
--- a/app/composer.json
+++ b/app/composer.json
@@ -10,13 +10,10 @@
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-intl": "*",
- "ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pcntl": "*",
"ext-pdo": "*",
- "ext-simplexml": "*",
- "ext-sodium": "*",
"composer/pcre": "^3.3.1",
"contributte/translation": "^2.0",
"latte/latte": "^3.0.3",
@@ -56,6 +53,7 @@
"symfony/polyfill-mbstring": "*"
},
"require-dev": {
+ "ext-simplexml": "*",
"jetbrains/phpstorm-attributes": "^1.0",
"nette/tester": "^2.4.3",
"php-parallel-lint/php-console-highlighter": "^1.0",
diff --git a/app/composer.lock b/app/composer.lock
index 643509b6c..3c220ef1e 100644
--- a/app/composer.lock
+++ b/app/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "ce19f674f584748cb60828e4e9b0f687",
+ "content-hash": "cd65d0895faaabd1296d4b6333ff4863",
"packages": [
{
"name": "composer/pcre",
@@ -3651,12 +3651,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
- "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487"
+ "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9f1d9b2460cdd0422e8cfd58763bf3156ad7f487",
- "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487",
+ "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/b33a18b5d222c63472a4b41f6fa3e15e591c9595",
+ "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595",
"shasum": ""
},
"conflict": {
@@ -3702,7 +3702,7 @@
"azuracast/azuracast": "<0.18.3",
"backdrop/backdrop": "<1.27.3|>=1.28,<1.28.2",
"backpack/crud": "<3.4.9",
- "backpack/filemanager": "<3.0.9",
+ "backpack/filemanager": "<2.0.2|>=3,<3.0.9",
"bacula-web/bacula-web": "<8.0.0.0-RC2-dev",
"badaso/core": "<2.7",
"bagisto/bagisto": "<2.1",
@@ -4034,7 +4034,7 @@
"mojo42/jirafeau": "<4.4",
"mongodb/mongodb": ">=1,<1.9.2",
"monolog/monolog": ">=1.8,<1.12",
- "moodle/moodle": "<4.3.6|>=4.4,<4.4.4",
+ "moodle/moodle": "<4.3.8|>=4.4,<4.4.4",
"mos/cimage": "<0.7.19",
"movim/moxl": ">=0.8,<=0.10",
"movingbytes/social-network": "<=1.2.1",
@@ -4122,7 +4122,7 @@
"phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5",
"phpoffice/common": "<0.2.9",
"phpoffice/phpexcel": "<1.8.1",
- "phpoffice/phpspreadsheet": "<1.29.2|>=2,<2.1.1|>=2.2,<2.3",
+ "phpoffice/phpspreadsheet": "<1.29.4|>=2,<2.1.3|>=2.2,<2.3.2|>=3.3,<3.4",
"phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36",
"phpservermon/phpservermon": "<3.6",
"phpsysinfo/phpsysinfo": "<3.4.3",
@@ -4176,7 +4176,7 @@
"rap2hpoutre/laravel-log-viewer": "<0.13",
"react/http": ">=0.7,<1.9",
"really-simple-plugins/complianz-gdpr": "<6.4.2",
- "redaxo/source": "<=5.17.1",
+ "redaxo/source": "<5.18",
"remdex/livehelperchat": "<4.29",
"reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7",
@@ -4232,7 +4232,7 @@
"slim/slim": "<2.6",
"slub/slub-events": "<3.0.3",
"smarty/smarty": "<4.5.3|>=5,<5.1.1",
- "snipe/snipe-it": "<7.0.10",
+ "snipe/snipe-it": "<=7.0.13",
"socalnick/scn-social-auth": "<1.15.2",
"socialiteproviders/steam": "<1.1",
"spatie/browsershot": "<3.57.4",
@@ -4243,7 +4243,7 @@
"squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1",
"ssddanbrown/bookstack": "<24.05.1",
"starcitizentools/citizen-skin": ">=2.6.3,<2.31",
- "statamic/cms": "<4.46|>=5.3,<5.6.2",
+ "statamic/cms": "<=5.16",
"stormpath/sdk": "<9.9.99",
"studio-42/elfinder": "<=2.1.64",
"studiomitte/friendlycaptcha": "<0.1.4",
@@ -4485,20 +4485,20 @@
"type": "tidelift"
}
],
- "time": "2024-11-13T19:05:18+00:00"
+ "time": "2024-11-19T21:04:39+00:00"
},
{
"name": "shipmonk/composer-dependency-analyser",
- "version": "1.7.0",
+ "version": "1.8.1",
"source": {
"type": "git",
"url": "https://github.com/shipmonk-rnd/composer-dependency-analyser.git",
- "reference": "bca862b2830a453734aee048eb0cdab82e5c9da3"
+ "reference": "0acd9d94be4d9397055ff012d0abf2ae88072e99"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/shipmonk-rnd/composer-dependency-analyser/zipball/bca862b2830a453734aee048eb0cdab82e5c9da3",
- "reference": "bca862b2830a453734aee048eb0cdab82e5c9da3",
+ "url": "https://api.github.com/repos/shipmonk-rnd/composer-dependency-analyser/zipball/0acd9d94be4d9397055ff012d0abf2ae88072e99",
+ "reference": "0acd9d94be4d9397055ff012d0abf2ae88072e99",
"shasum": ""
},
"require": {
@@ -4507,17 +4507,17 @@
"php": "^7.2 || ^8.0"
},
"require-dev": {
- "editorconfig-checker/editorconfig-checker": "^10.3.0",
- "ergebnis/composer-normalize": "^2.19",
+ "editorconfig-checker/editorconfig-checker": "^10.6.0",
+ "ergebnis/composer-normalize": "^2.19.0",
"ext-dom": "*",
"ext-libxml": "*",
- "phpcompatibility/php-compatibility": "^9.3",
- "phpstan/phpstan": "^1.10.63",
- "phpstan/phpstan-phpunit": "^1.1.1",
- "phpstan/phpstan-strict-rules": "^1.2.3",
- "phpunit/phpunit": "^8.5.28 || ^9.5.20",
- "shipmonk/name-collision-detector": "^2.0.0",
- "slevomat/coding-standard": "^8.0.1"
+ "phpcompatibility/php-compatibility": "^9.3.5",
+ "phpstan/phpstan": "^1.12.3",
+ "phpstan/phpstan-phpunit": "^1.4.0",
+ "phpstan/phpstan-strict-rules": "^1.6.0",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "shipmonk/name-collision-detector": "^2.1.1",
+ "slevomat/coding-standard": "^8.15.0"
},
"bin": [
"bin/composer-dependency-analyser"
@@ -4549,9 +4549,9 @@
],
"support": {
"issues": "https://github.com/shipmonk-rnd/composer-dependency-analyser/issues",
- "source": "https://github.com/shipmonk-rnd/composer-dependency-analyser/tree/1.7.0"
+ "source": "https://github.com/shipmonk-rnd/composer-dependency-analyser/tree/1.8.1"
},
- "time": "2024-08-08T08:12:32+00:00"
+ "time": "2024-11-18T12:58:21+00:00"
},
{
"name": "slevomat/coding-standard",
@@ -4844,14 +4844,13 @@
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-intl": "*",
- "ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pcntl": "*",
- "ext-pdo": "*",
- "ext-simplexml": "*",
- "ext-sodium": "*"
+ "ext-pdo": "*"
+ },
+ "platform-dev": {
+ "ext-simplexml": "*"
},
- "platform-dev": [],
"plugin-api-version": "2.6.0"
}
diff --git a/app/psalm.xml b/app/psalm.xml
index 4dea9e9c8..10575a7eb 100644
--- a/app/psalm.xml
+++ b/app/psalm.xml
@@ -23,6 +23,9 @@
+
+
+
diff --git a/app/vendor/composer/installed.json b/app/vendor/composer/installed.json
index 5ae2bdbb4..08f49694c 100644
--- a/app/vendor/composer/installed.json
+++ b/app/vendor/composer/installed.json
@@ -2468,12 +2468,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
- "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487"
+ "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9f1d9b2460cdd0422e8cfd58763bf3156ad7f487",
- "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487",
+ "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/b33a18b5d222c63472a4b41f6fa3e15e591c9595",
+ "reference": "b33a18b5d222c63472a4b41f6fa3e15e591c9595",
"shasum": ""
},
"conflict": {
@@ -2519,7 +2519,7 @@
"azuracast/azuracast": "<0.18.3",
"backdrop/backdrop": "<1.27.3|>=1.28,<1.28.2",
"backpack/crud": "<3.4.9",
- "backpack/filemanager": "<3.0.9",
+ "backpack/filemanager": "<2.0.2|>=3,<3.0.9",
"bacula-web/bacula-web": "<8.0.0.0-RC2-dev",
"badaso/core": "<2.7",
"bagisto/bagisto": "<2.1",
@@ -2851,7 +2851,7 @@
"mojo42/jirafeau": "<4.4",
"mongodb/mongodb": ">=1,<1.9.2",
"monolog/monolog": ">=1.8,<1.12",
- "moodle/moodle": "<4.3.6|>=4.4,<4.4.4",
+ "moodle/moodle": "<4.3.8|>=4.4,<4.4.4",
"mos/cimage": "<0.7.19",
"movim/moxl": ">=0.8,<=0.10",
"movingbytes/social-network": "<=1.2.1",
@@ -2939,7 +2939,7 @@
"phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5",
"phpoffice/common": "<0.2.9",
"phpoffice/phpexcel": "<1.8.1",
- "phpoffice/phpspreadsheet": "<1.29.2|>=2,<2.1.1|>=2.2,<2.3",
+ "phpoffice/phpspreadsheet": "<1.29.4|>=2,<2.1.3|>=2.2,<2.3.2|>=3.3,<3.4",
"phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36",
"phpservermon/phpservermon": "<3.6",
"phpsysinfo/phpsysinfo": "<3.4.3",
@@ -2993,7 +2993,7 @@
"rap2hpoutre/laravel-log-viewer": "<0.13",
"react/http": ">=0.7,<1.9",
"really-simple-plugins/complianz-gdpr": "<6.4.2",
- "redaxo/source": "<=5.17.1",
+ "redaxo/source": "<5.18",
"remdex/livehelperchat": "<4.29",
"reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7",
@@ -3049,7 +3049,7 @@
"slim/slim": "<2.6",
"slub/slub-events": "<3.0.3",
"smarty/smarty": "<4.5.3|>=5,<5.1.1",
- "snipe/snipe-it": "<7.0.10",
+ "snipe/snipe-it": "<=7.0.13",
"socalnick/scn-social-auth": "<1.15.2",
"socialiteproviders/steam": "<1.1",
"spatie/browsershot": "<3.57.4",
@@ -3060,7 +3060,7 @@
"squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1",
"ssddanbrown/bookstack": "<24.05.1",
"starcitizentools/citizen-skin": ">=2.6.3,<2.31",
- "statamic/cms": "<4.46|>=5.3,<5.6.2",
+ "statamic/cms": "<=5.16",
"stormpath/sdk": "<9.9.99",
"studio-42/elfinder": "<=2.1.64",
"studiomitte/friendlycaptcha": "<0.1.4",
@@ -3266,7 +3266,7 @@
"zfr/zfr-oauth2-server-module": "<0.1.2",
"zoujingli/thinkadmin": "<=6.1.53"
},
- "time": "2024-11-13T19:05:18+00:00",
+ "time": "2024-11-19T21:04:39+00:00",
"default-branch": true,
"type": "metapackage",
"notification-url": "https://packagist.org/downloads/",
@@ -3307,17 +3307,17 @@
},
{
"name": "shipmonk/composer-dependency-analyser",
- "version": "1.7.0",
- "version_normalized": "1.7.0.0",
+ "version": "1.8.1",
+ "version_normalized": "1.8.1.0",
"source": {
"type": "git",
"url": "https://github.com/shipmonk-rnd/composer-dependency-analyser.git",
- "reference": "bca862b2830a453734aee048eb0cdab82e5c9da3"
+ "reference": "0acd9d94be4d9397055ff012d0abf2ae88072e99"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/shipmonk-rnd/composer-dependency-analyser/zipball/bca862b2830a453734aee048eb0cdab82e5c9da3",
- "reference": "bca862b2830a453734aee048eb0cdab82e5c9da3",
+ "url": "https://api.github.com/repos/shipmonk-rnd/composer-dependency-analyser/zipball/0acd9d94be4d9397055ff012d0abf2ae88072e99",
+ "reference": "0acd9d94be4d9397055ff012d0abf2ae88072e99",
"shasum": ""
},
"require": {
@@ -3326,19 +3326,19 @@
"php": "^7.2 || ^8.0"
},
"require-dev": {
- "editorconfig-checker/editorconfig-checker": "^10.3.0",
- "ergebnis/composer-normalize": "^2.19",
+ "editorconfig-checker/editorconfig-checker": "^10.6.0",
+ "ergebnis/composer-normalize": "^2.19.0",
"ext-dom": "*",
"ext-libxml": "*",
- "phpcompatibility/php-compatibility": "^9.3",
- "phpstan/phpstan": "^1.10.63",
- "phpstan/phpstan-phpunit": "^1.1.1",
- "phpstan/phpstan-strict-rules": "^1.2.3",
- "phpunit/phpunit": "^8.5.28 || ^9.5.20",
- "shipmonk/name-collision-detector": "^2.0.0",
- "slevomat/coding-standard": "^8.0.1"
- },
- "time": "2024-08-08T08:12:32+00:00",
+ "phpcompatibility/php-compatibility": "^9.3.5",
+ "phpstan/phpstan": "^1.12.3",
+ "phpstan/phpstan-phpunit": "^1.4.0",
+ "phpstan/phpstan-strict-rules": "^1.6.0",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "shipmonk/name-collision-detector": "^2.1.1",
+ "slevomat/coding-standard": "^8.15.0"
+ },
+ "time": "2024-11-18T12:58:21+00:00",
"bin": [
"bin/composer-dependency-analyser"
],
@@ -3370,7 +3370,7 @@
],
"support": {
"issues": "https://github.com/shipmonk-rnd/composer-dependency-analyser/issues",
- "source": "https://github.com/shipmonk-rnd/composer-dependency-analyser/tree/1.7.0"
+ "source": "https://github.com/shipmonk-rnd/composer-dependency-analyser/tree/1.8.1"
},
"install-path": "../shipmonk/composer-dependency-analyser"
},
diff --git a/app/vendor/composer/installed.php b/app/vendor/composer/installed.php
index da3013274..a00a6511a 100644
--- a/app/vendor/composer/installed.php
+++ b/app/vendor/composer/installed.php
@@ -403,7 +403,7 @@
'roave/security-advisories' => array(
'pretty_version' => 'dev-latest',
'version' => 'dev-latest',
- 'reference' => '9f1d9b2460cdd0422e8cfd58763bf3156ad7f487',
+ 'reference' => 'b33a18b5d222c63472a4b41f6fa3e15e591c9595',
'type' => 'metapackage',
'install_path' => null,
'aliases' => array(
@@ -412,9 +412,9 @@
'dev_requirement' => true,
),
'shipmonk/composer-dependency-analyser' => array(
- 'pretty_version' => '1.7.0',
- 'version' => '1.7.0.0',
- 'reference' => 'bca862b2830a453734aee048eb0cdab82e5c9da3',
+ 'pretty_version' => '1.8.1',
+ 'version' => '1.8.1.0',
+ 'reference' => '0acd9d94be4d9397055ff012d0abf2ae88072e99',
'type' => 'library',
'install_path' => __DIR__ . '/../shipmonk/composer-dependency-analyser',
'aliases' => array(),
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/README.md b/app/vendor/shipmonk/composer-dependency-analyser/README.md
index 33c79ae38..3f1923671 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/README.md
+++ b/app/vendor/shipmonk/composer-dependency-analyser/README.md
@@ -5,7 +5,7 @@
- ⚙️ **Configurable:** Fine-grained ignores via PHP config
- 🕸️ **Lightweight:** No composer dependencies
- 🍰 **Easy-to-use:** No config needed for first try
-- ✨ **Compatible:** PHP 7.2 - 8.3
+- ✨ **Compatible:** PHP 7.2 - 8.4
## Comparison:
@@ -49,7 +49,7 @@ Found unused dependencies!
```
## Detected issues:
-This tool reads your `composer.json` and scans all paths listed in `autoload` & `autoload-dev` sections while analysing:
+This tool reads your `composer.json` and scans all paths listed in `autoload` & `autoload-dev` sections while analysing you dependencies (both **packages and PHP extensions**).
### Shadowed dependencies
- Those are dependencies of your dependencies, which are not listed in `composer.json`
@@ -84,6 +84,7 @@ This tool reads your `composer.json` and scans all paths listed in `autoload` &
- `--verbose` to see more example classes & usages
- `--show-all-usages` to see all usages
- `--format` to use different output format, available are: `console` (default), `junit`
+- `--disable-ext-analysis` to disable php extensions analysis (e.g. `ext-xml`)
- `--ignore-unknown-classes` to globally ignore unknown classes
- `--ignore-unknown-functions` to globally ignore unknown functions
- `--ignore-shadow-deps` to globally ignore shadow dependencies
@@ -128,6 +129,7 @@ return $config
//// Adjust analysis
->enableAnalysisOfUnusedDevDependencies() // dev packages are often used only in CI, so this is not enabled by default
->disableReportingUnmatchedIgnores() // do not report ignores that never matched any error
+ ->disableExtensionsAnalysis() // do not analyse ext-* dependencies
//// Use symbols from yaml/xml/neon files
// - designed for DIC config files (see below)
@@ -160,8 +162,14 @@ Another approach for DIC-only usages is to scan the generated php file, but that
### Scanning codebase located elsewhere:
- This can be done by pointing `--composer-json` to `composer.json` of the other codebase
-## Limitations:
-- Extension dependencies are not analysed (e.g. `ext-json`)
+### Disable colored output:
+- Set `NO_COLOR` environment variable to disable colored output:
+```
+NO_COLOR=1 vendor/bin/composer-dependency-analyser
+```
+
+## Recommendations:
+- For precise `ext-*` analysis, your enabled extensions of your php runtime should be superset of those used in the scanned project
## Contributing:
- Check your code by `composer check`
@@ -169,5 +177,5 @@ Another approach for DIC-only usages is to scan the generated php file, but that
- All functionality must be tested
## Supported PHP versions
-- Runtime requires PHP 7.2 - 8.3
+- Runtime requires PHP 7.2 - 8.4
- Scanned codebase should use PHP >= 5.3
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/bin/composer-dependency-analyser b/app/vendor/shipmonk/composer-dependency-analyser/bin/composer-dependency-analyser
index 2e39d8171..a93a61d1a 100755
--- a/app/vendor/shipmonk/composer-dependency-analyser/bin/composer-dependency-analyser
+++ b/app/vendor/shipmonk/composer-dependency-analyser/bin/composer-dependency-analyser
@@ -27,9 +27,10 @@ spl_autoload_register(static function (string $class) use ($psr4Prefix): void {
/** @var non-empty-string $cwd */
$cwd = getcwd();
+$noColor = getenv('NO_COLOR') !== false;
-$stdOutPrinter = new Printer(STDOUT);
-$stdErrPrinter = new Printer(STDERR);
+$stdOutPrinter = new Printer(STDOUT, $noColor);
+$stdErrPrinter = new Printer(STDERR, $noColor);
$initializer = new Initializer($cwd, $stdOutPrinter, $stdErrPrinter);
$stopwatch = new Stopwatch();
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/composer.json b/app/vendor/shipmonk/composer-dependency-analyser/composer.json
index c2af7b2e6..3e792f077 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/composer.json
+++ b/app/vendor/shipmonk/composer-dependency-analyser/composer.json
@@ -26,15 +26,15 @@
"require-dev": {
"ext-dom": "*",
"ext-libxml": "*",
- "editorconfig-checker/editorconfig-checker": "^10.3.0",
- "ergebnis/composer-normalize": "^2.19",
- "phpcompatibility/php-compatibility": "^9.3",
- "phpstan/phpstan": "^1.10.63",
- "phpstan/phpstan-phpunit": "^1.1.1",
- "phpstan/phpstan-strict-rules": "^1.2.3",
- "phpunit/phpunit": "^8.5.28 || ^9.5.20",
- "shipmonk/name-collision-detector": "^2.0.0",
- "slevomat/coding-standard": "^8.0.1"
+ "editorconfig-checker/editorconfig-checker": "^10.6.0",
+ "ergebnis/composer-normalize": "^2.19.0",
+ "phpcompatibility/php-compatibility": "^9.3.5",
+ "phpstan/phpstan": "^1.12.3",
+ "phpstan/phpstan-phpunit": "^1.4.0",
+ "phpstan/phpstan-strict-rules": "^1.6.0",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20",
+ "shipmonk/name-collision-detector": "^2.1.1",
+ "slevomat/coding-standard": "^8.15.0"
},
"autoload": {
"psr-4": {
@@ -67,15 +67,20 @@
"@check:types",
"@check:tests",
"@check:self",
- "@check:collisions"
+ "@check:collisions",
+ "@check:scripts"
],
"check:collisions": "detect-collisions src tests",
- "check:composer": "composer normalize --dry-run --no-check-lock --no-update-lock",
+ "check:composer": [
+ "composer normalize --dry-run --no-check-lock --no-update-lock",
+ "composer validate --strict"
+ ],
"check:cs": "phpcs",
"check:ec": "ec src tests",
+ "check:scripts": "phpstan analyse -vv --ansi --level=6 scripts/*.php",
"check:self": "bin/composer-dependency-analyser",
"check:tests": "phpunit -vvv tests",
- "check:types": "phpstan analyse -vvv --ansi",
+ "check:types": "phpstan analyse -vv --ansi",
"fix:cs": "phpcbf"
}
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Analyser.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Analyser.php
index 2c984bd0e..d77416c6c 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Analyser.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Analyser.php
@@ -45,6 +45,24 @@
class Analyser
{
+ /**
+ * Those are core PHP extensions, that can never be disabled
+ * There are more PHP "core" extensions, that are bundled by default, but PHP can be compiled without them
+ * You can check which are added conditionally in https://github.com/php/php-src/tree/master/ext (see config.w32 files)
+ */
+ private const CORE_EXTENSIONS = [
+ 'ext-core',
+ 'ext-date',
+ 'ext-json',
+ 'ext-hash',
+ 'ext-pcre',
+ 'ext-phar',
+ 'ext-reflection',
+ 'ext-spl',
+ 'ext-random',
+ 'ext-standard',
+ ];
+
/**
* @var Stopwatch
*/
@@ -73,7 +91,7 @@ class Analyser
private $classmap = [];
/**
- * package name => is dev dependency
+ * package or ext-* => is dev dependency
*
* @var array
*/
@@ -87,15 +105,29 @@ class Analyser
private $ignoredSymbols;
/**
- * function name => path
+ * custom function name => path
*
* @var array
*/
private $definedFunctions = [];
+ /**
+ * kind => [symbol name => ext-*]
+ *
+ * @var array>
+ */
+ private $extensionSymbols = [];
+
+ /**
+ * lowercase symbol name => kind
+ *
+ * @var array
+ */
+ private $extensionSymbolKinds = [];
+
/**
* @param array $classLoaders vendorDir => ClassLoader (e.g. result of \Composer\Autoload\ClassLoader::getRegisteredLoaders())
- * @param array $composerJsonDependencies package name => is dev dependency
+ * @param array $composerJsonDependencies package or ext-* => is dev dependency
*/
public function __construct(
Stopwatch $stopwatch,
@@ -107,11 +139,11 @@ public function __construct(
{
$this->stopwatch = $stopwatch;
$this->config = $config;
- $this->composerJsonDependencies = $composerJsonDependencies;
+ $this->composerJsonDependencies = $this->filterDependencies($composerJsonDependencies, $config);
$this->vendorDirs = array_keys($classLoaders + [$defaultVendorDir => null]);
$this->classLoaders = array_values($classLoaders);
- $this->initExistingSymbols();
+ $this->initExistingSymbols($config);
}
/**
@@ -129,8 +161,8 @@ public function run(): AnalysisResult
$prodOnlyInDevErrors = [];
$unusedErrors = [];
- $usedPackages = [];
- $prodPackagesUsedInProdPath = [];
+ $usedDependencies = [];
+ $prodDependenciesUsedInProdPath = [];
$usages = [];
@@ -143,66 +175,71 @@ public function run(): AnalysisResult
foreach ($usedSymbolsByKind as $kind => $usedSymbols) {
foreach ($usedSymbols as $usedSymbol => $lineNumbers) {
- $usedSymbolNameForIgnoreCheck = $kind === SymbolKind::FUNCTION ? strtolower($usedSymbol) : $usedSymbol;
+ $normalizedUsedSymbolName = $kind === SymbolKind::FUNCTION ? strtolower($usedSymbol) : $usedSymbol;
- if (isset($this->ignoredSymbols[$usedSymbolNameForIgnoreCheck])) {
+ if (isset($this->ignoredSymbols[$normalizedUsedSymbolName])) {
continue;
}
- $symbolPath = $this->getSymbolPath($usedSymbol, $kind);
+ if (isset($this->extensionSymbols[$kind][$normalizedUsedSymbolName])) {
+ $dependencyName = $this->extensionSymbols[$kind][$normalizedUsedSymbolName];
+
+ } else {
+ $symbolPath = $this->getSymbolPath($usedSymbol, $kind);
- if ($symbolPath === null) {
- if ($kind === SymbolKind::CLASSLIKE && !$ignoreList->shouldIgnoreUnknownClass($usedSymbol, $filePath)) {
- foreach ($lineNumbers as $lineNumber) {
- $unknownClassErrors[$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ if ($symbolPath === null) {
+ if ($kind === SymbolKind::CLASSLIKE && !$ignoreList->shouldIgnoreUnknownClass($usedSymbol, $filePath)) {
+ foreach ($lineNumbers as $lineNumber) {
+ $unknownClassErrors[$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ }
}
- }
- if ($kind === SymbolKind::FUNCTION && !$ignoreList->shouldIgnoreUnknownFunction($usedSymbol, $filePath)) {
- foreach ($lineNumbers as $lineNumber) {
- $unknownFunctionErrors[$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ if ($kind === SymbolKind::FUNCTION && !$ignoreList->shouldIgnoreUnknownFunction($usedSymbol, $filePath)) {
+ foreach ($lineNumbers as $lineNumber) {
+ $unknownFunctionErrors[$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ }
}
+
+ continue;
}
- continue;
- }
+ if (!$this->isVendorPath($symbolPath)) {
+ continue; // local class
+ }
- if (!$this->isVendorPath($symbolPath)) {
- continue; // local class
+ $dependencyName = $this->getPackageNameFromVendorPath($symbolPath);
}
- $packageName = $this->getPackageNameFromVendorPath($symbolPath);
-
if (
- $this->isShadowDependency($packageName)
- && !$ignoreList->shouldIgnoreError(ErrorType::SHADOW_DEPENDENCY, $filePath, $packageName)
+ $this->isShadowDependency($dependencyName)
+ && !$ignoreList->shouldIgnoreError(ErrorType::SHADOW_DEPENDENCY, $filePath, $dependencyName)
) {
foreach ($lineNumbers as $lineNumber) {
- $shadowErrors[$packageName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ $shadowErrors[$dependencyName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
}
}
if (
!$isDevFilePath
- && $this->isDevDependency($packageName)
- && !$ignoreList->shouldIgnoreError(ErrorType::DEV_DEPENDENCY_IN_PROD, $filePath, $packageName)
+ && $this->isDevDependency($dependencyName)
+ && !$ignoreList->shouldIgnoreError(ErrorType::DEV_DEPENDENCY_IN_PROD, $filePath, $dependencyName)
) {
foreach ($lineNumbers as $lineNumber) {
- $devInProdErrors[$packageName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ $devInProdErrors[$dependencyName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
}
}
if (
!$isDevFilePath
- && !$this->isDevDependency($packageName)
+ && !$this->isDevDependency($dependencyName)
) {
- $prodPackagesUsedInProdPath[$packageName] = true;
+ $prodDependenciesUsedInProdPath[$dependencyName] = true;
}
- $usedPackages[$packageName] = true;
+ $usedDependencies[$dependencyName] = true;
foreach ($lineNumbers as $lineNumber) {
- $usages[$packageName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
+ $usages[$dependencyName][$usedSymbol][] = new SymbolUsage($filePath, $lineNumber, $kind);
}
}
}
@@ -215,19 +252,31 @@ public function run(): AnalysisResult
continue;
}
- $symbolPath = $this->getSymbolPath($forceUsedSymbol, null);
+ if (
+ isset($this->extensionSymbols[SymbolKind::FUNCTION][$forceUsedSymbol])
+ || isset($this->extensionSymbols[SymbolKind::CONSTANT][$forceUsedSymbol])
+ || isset($this->extensionSymbols[SymbolKind::CLASSLIKE][$forceUsedSymbol])
+ ) {
+ $forceUsedDependency = $this->extensionSymbols[SymbolKind::FUNCTION][$forceUsedSymbol]
+ ?? $this->extensionSymbols[SymbolKind::CONSTANT][$forceUsedSymbol]
+ ?? $this->extensionSymbols[SymbolKind::CLASSLIKE][$forceUsedSymbol];
+ } else {
+ $symbolPath = $this->getSymbolPath($forceUsedSymbol, null);
+
+ if ($symbolPath === null || !$this->isVendorPath($symbolPath)) {
+ continue;
+ }
- if ($symbolPath === null || !$this->isVendorPath($symbolPath)) {
- continue;
+ $forceUsedDependency = $this->getPackageNameFromVendorPath($symbolPath);
}
- $forceUsedPackage = $this->getPackageNameFromVendorPath($symbolPath);
- $usedPackages[$forceUsedPackage] = true;
- $forceUsedPackages[$forceUsedPackage] = true;
+ $usedDependencies[$forceUsedDependency] = true;
+ $forceUsedPackages[$forceUsedDependency] = true;
}
if ($this->config->shouldReportUnusedDevDependencies()) {
$dependenciesForUnusedAnalysis = array_keys($this->composerJsonDependencies);
+
} else {
$dependenciesForUnusedAnalysis = array_keys(array_filter($this->composerJsonDependencies, static function (bool $devDependency) {
return !$devDependency; // dev deps are typically used only in CI
@@ -236,7 +285,8 @@ public function run(): AnalysisResult
$unusedDependencies = array_diff(
$dependenciesForUnusedAnalysis,
- array_keys($usedPackages)
+ array_keys($usedDependencies),
+ self::CORE_EXTENSIONS
);
foreach ($unusedDependencies as $unusedDependency) {
@@ -250,9 +300,10 @@ public function run(): AnalysisResult
}));
$prodPackagesUsedOnlyInDev = array_diff(
$prodDependencies,
- array_keys($prodPackagesUsedInProdPath),
+ array_keys($prodDependenciesUsedInProdPath),
array_keys($forceUsedPackages), // we dont know where are those used, lets not report them
- $unusedDependencies
+ $unusedDependencies,
+ self::CORE_EXTENSIONS
);
foreach ($prodPackagesUsedOnlyInDev as $prodPackageUsedOnlyInDev) {
@@ -340,7 +391,9 @@ private function getUsedSymbolsInFile(string $filePath): array
throw new InvalidPathException("Unable to get contents of '$filePath'");
}
- return (new UsedSymbolExtractor($code))->parseUsedSymbols();
+ return (new UsedSymbolExtractor($code))->parseUsedSymbols(
+ $this->extensionSymbolKinds
+ );
}
/**
@@ -450,7 +503,7 @@ private function normalizePath(string $filePath): string
return Path::normalize($filePath);
}
- private function initExistingSymbols(): void
+ private function initExistingSymbols(Configuration $config): void
{
$this->ignoredSymbols = [
// built-in types
@@ -485,9 +538,25 @@ private function initExistingSymbols(): void
'Composer\\Autoload\\ClassLoader' => true,
];
- /** @var string $constantName */
- foreach (get_defined_constants() as $constantName => $constantValue) {
- $this->ignoredSymbols[$constantName] = true;
+ /** @var array> $definedConstants */
+ $definedConstants = get_defined_constants(true);
+
+ foreach ($definedConstants as $constantExtension => $constants) {
+ foreach ($constants as $constantName => $_) {
+ if ($constantExtension === 'user' || !$config->shouldAnalyseExtensions()) {
+ $this->ignoredSymbols[$constantName] = true;
+
+ } else {
+ $extensionName = $this->getNormalizedExtensionName($constantExtension);
+
+ if (in_array($extensionName, self::CORE_EXTENSIONS, true)) {
+ $this->ignoredSymbols[$constantName] = true;
+ } else {
+ $this->extensionSymbols[SymbolKind::CONSTANT][$constantName] = $extensionName;
+ $this->extensionSymbolKinds[strtolower($constantName)] = SymbolKind::CONSTANT;
+ }
+ }
+ }
}
foreach (get_defined_functions() as $functionNames) {
@@ -495,10 +564,19 @@ private function initExistingSymbols(): void
$reflectionFunction = new ReflectionFunction($functionName);
$functionFilePath = $reflectionFunction->getFileName();
- if ($reflectionFunction->getExtension() === null && is_string($functionFilePath)) {
- $this->definedFunctions[$functionName] = Path::normalize($functionFilePath);
+ if ($reflectionFunction->getExtension() === null) {
+ if (is_string($functionFilePath)) {
+ $this->definedFunctions[$functionName] = Path::normalize($functionFilePath);
+ }
} else {
- $this->ignoredSymbols[$functionName] = true;
+ $extensionName = $this->getNormalizedExtensionName($reflectionFunction->getExtension()->name);
+
+ if (in_array($extensionName, self::CORE_EXTENSIONS, true) || !$config->shouldAnalyseExtensions()) {
+ $this->ignoredSymbols[$functionName] = true;
+ } else {
+ $this->extensionSymbols[SymbolKind::FUNCTION][$functionName] = $extensionName;
+ $this->extensionSymbolKinds[$functionName] = SymbolKind::FUNCTION;
+ }
}
}
}
@@ -511,11 +589,44 @@ private function initExistingSymbols(): void
foreach ($classLikes as $classLikeNames) {
foreach ($classLikeNames as $classLikeName) {
- if ((new ReflectionClass($classLikeName))->getExtension() !== null) {
- $this->ignoredSymbols[$classLikeName] = true;
+ $classReflection = new ReflectionClass($classLikeName);
+
+ if ($classReflection->getExtension() !== null) {
+ $extensionName = $this->getNormalizedExtensionName($classReflection->getExtension()->name);
+
+ if (in_array($extensionName, self::CORE_EXTENSIONS, true) || !$config->shouldAnalyseExtensions()) {
+ $this->ignoredSymbols[$classLikeName] = true;
+ } else {
+ $this->extensionSymbols[SymbolKind::CLASSLIKE][$classLikeName] = $extensionName;
+ $this->extensionSymbolKinds[strtolower($classLikeName)] = SymbolKind::CLASSLIKE;
+ }
}
}
}
}
+ private function getNormalizedExtensionName(string $extension): string
+ {
+ return 'ext-' . ComposerJson::normalizeExtensionName($extension);
+ }
+
+ /**
+ * @param array $dependencies
+ * @return array
+ */
+ private function filterDependencies(array $dependencies, Configuration $config): array
+ {
+ $filtered = [];
+
+ foreach ($dependencies as $dependency => $isDevDependency) {
+ if (!$config->shouldAnalyseExtensions() && strpos($dependency, 'ext-') === 0) {
+ continue;
+ }
+
+ $filtered[$dependency] = $isDevDependency;
+ }
+
+ return $filtered;
+ }
+
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Cli.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Cli.php
index f4d90edfa..ceb7f269a 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Cli.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Cli.php
@@ -3,11 +3,15 @@
namespace ShipMonk\ComposerDependencyAnalyser;
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidCliException;
+use function array_keys;
use function array_slice;
use function is_dir;
use function is_file;
+use function levenshtein;
+use function strlen;
use function strpos;
use function substr;
+use function trim;
class Cli
{
@@ -16,6 +20,7 @@ class Cli
'version' => false,
'help' => false,
'verbose' => false,
+ 'disable-ext-analysis' => false,
'ignore-shadow-deps' => false,
'ignore-unused-deps' => false,
'ignore-dev-in-prod-deps' => false,
@@ -54,7 +59,8 @@ public function __construct(string $cwd, array $argv)
$startsWithDashDash = strpos($arg, '--') === 0;
if ($startsWithDash && !$startsWithDashDash) {
- throw new InvalidCliException("Unknown option $arg, see --help");
+ $suggestedOption = $this->suggestOption($arg);
+ throw new InvalidCliException("Unknown option $arg, $suggestedOption");
}
if (!$startsWithDashDash) {
@@ -62,7 +68,8 @@ public function __construct(string $cwd, array $argv)
throw new InvalidCliException("Cannot pass paths ($arg) to analyse as arguments, use --config instead.");
}
- throw new InvalidCliException("Unknown argument $arg, see --help");
+ $suggestedOption = $this->suggestOption($arg);
+ throw new InvalidCliException("Unknown argument $arg, $suggestedOption");
}
/** @var string $noDashesArg this is never false as we know it starts with -- */
@@ -70,7 +77,8 @@ public function __construct(string $cwd, array $argv)
$optionName = $this->getKnownOptionName($noDashesArg);
if ($optionName === null) {
- throw new InvalidCliException("Unknown option $arg, see --help");
+ $suggestedOption = $this->suggestOption($noDashesArg);
+ throw new InvalidCliException("Unknown option $arg, $suggestedOption");
}
if ($this->isOptionWithRequiredValue($optionName)) {
@@ -91,6 +99,10 @@ public function __construct(string $cwd, array $argv)
$this->providedOptions[$optionName] = $optionArgument;
}
} else {
+ if ($this->getOptionArgumentAfterAssign($arg) !== null) {
+ throw new InvalidCliException("Option --$optionName does not accept arguments, see --help");
+ }
+
$this->providedOptions[$optionName] = true;
}
}
@@ -115,7 +127,10 @@ private function isOptionWithRequiredValue(string $optionName): bool
private function getKnownOptionName(string $option): ?string
{
foreach (self::OPTIONS as $knownOption => $needsArgument) {
- if (strpos($option, $knownOption) === 0) {
+ if (
+ strpos($option, $knownOption) === 0
+ && (strlen($option) === strlen($knownOption) || $option[strlen($knownOption)] === '=')
+ ) {
return $knownOption;
}
}
@@ -139,6 +154,10 @@ public function getProvidedOptions(): CliOptions
$options->verbose = true;
}
+ if (isset($this->providedOptions['disable-ext-analysis'])) {
+ $options->disableExtAnalysis = true;
+ }
+
if (isset($this->providedOptions['ignore-shadow-deps'])) {
$options->ignoreShadowDeps = true;
}
@@ -186,4 +205,29 @@ public function getProvidedOptions(): CliOptions
return $options;
}
+ /**
+ * Params inspired by tracy/tracy
+ */
+ private function suggestOption(string $input): string
+ {
+ $value = trim($input, '-');
+ $options = array_keys(self::OPTIONS);
+
+ $bestGuess = null;
+ $minDistance = (strlen($value) / 4 + 1) * 10 + .1;
+
+ foreach ($options as $option) {
+ $distance = levenshtein($option, $value, 9, 11, 9);
+
+ if ($distance > 0 && $distance < $minDistance) {
+ $minDistance = $distance;
+ $bestGuess = $option;
+ }
+ }
+
+ return $bestGuess === null
+ ? 'see --help'
+ : "did you mean --$bestGuess?";
+ }
+
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/CliOptions.php b/app/vendor/shipmonk/composer-dependency-analyser/src/CliOptions.php
index 3656225ee..3eeaf15b5 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/CliOptions.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/CliOptions.php
@@ -20,6 +20,11 @@ class CliOptions
*/
public $verbose = null;
+ /**
+ * @var true|null
+ */
+ public $disableExtAnalysis = null;
+
/**
* @var true|null
*/
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/ComposerJson.php b/app/vendor/shipmonk/composer-dependency-analyser/src/ComposerJson.php
index 4e1d48f5c..a35149924 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/ComposerJson.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/ComposerJson.php
@@ -23,6 +23,7 @@
use function realpath;
use function str_replace;
use function strpos;
+use function strtolower;
use function strtr;
use function trim;
use const ARRAY_FILTER_USE_KEY;
@@ -44,7 +45,7 @@ class ComposerJson
public $composerAutoloadPath;
/**
- * Package => isDev
+ * Package or ext-* => isDev
*
* @readonly
* @var array
@@ -99,20 +100,54 @@ public function __construct(
$this->extractAutoloadExcludeRegexes($basePath, $composerJsonData['autoload-dev']['exclude-from-classmap'] ?? [], true)
);
+ $filterExtensions = static function (string $dependency): bool {
+ return strpos($dependency, 'ext-') === 0;
+ };
$filterPackages = static function (string $package): bool {
return strpos($package, '/') !== false;
};
- $this->dependencies = array_merge(
+ $this->dependencies = $this->normalizeNames(array_merge(
array_fill_keys(array_keys(array_filter($requiredPackages, $filterPackages, ARRAY_FILTER_USE_KEY)), false),
- array_fill_keys(array_keys(array_filter($requiredDevPackages, $filterPackages, ARRAY_FILTER_USE_KEY)), true)
- );
+ array_fill_keys(array_keys(array_filter($requiredPackages, $filterExtensions, ARRAY_FILTER_USE_KEY)), false),
+ array_fill_keys(array_keys(array_filter($requiredDevPackages, $filterPackages, ARRAY_FILTER_USE_KEY)), true),
+ array_fill_keys(array_keys(array_filter($requiredDevPackages, $filterExtensions, ARRAY_FILTER_USE_KEY)), true)
+ ));
if (count($this->dependencies) === 0) {
- throw new InvalidConfigException("No packages found in $composerJsonPath file.");
+ throw new InvalidConfigException("No dependencies found in $composerJsonPath file.");
}
}
+ /**
+ * @param array $dependencies
+ * @return array
+ */
+ private function normalizeNames(array $dependencies): array
+ {
+ $normalized = [];
+
+ foreach ($dependencies as $dependency => $isDev) {
+ if (strpos($dependency, 'ext-') === 0) {
+ $key = self::normalizeExtensionName($dependency);
+ } else {
+ $key = $dependency;
+ }
+
+ $normalized[$key] = $isDev;
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * Zend Opcache -> zend-opcache
+ */
+ public static function normalizeExtensionName(string $extension): string
+ {
+ return str_replace(' ', '-', strtolower($extension));
+ }
+
/**
* @param array> $autoload
* @return array
@@ -196,10 +231,8 @@ private function resolveAutoloadExclude(string $basePath, string $pathPattern):
$path = preg_replace_callback(
'{^((?:(?:\\\\\\.){1,2}+/)+)}',
static function ($matches) use (&$updir): string {
- if (isset($matches[1]) && $matches[1] !== '') {
- // undo preg_quote for the matched string
- $updir = str_replace('\\.', '.', $matches[1]);
- }
+ // undo preg_quote for the matched string
+ $updir = str_replace('\\.', '.', $matches[1]);
return '';
},
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Configuration.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Configuration.php
index 7fb72918c..8883145e5 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Configuration.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Configuration.php
@@ -14,6 +14,11 @@
class Configuration
{
+ /**
+ * @var bool
+ */
+ private $extensionsAnalysis = true;
+
/**
* @var bool
*/
@@ -67,12 +72,12 @@ class Configuration
/**
* @var array>
*/
- private $ignoredErrorsOnPackage = [];
+ private $ignoredErrorsOnDependency = [];
/**
* @var array>>
*/
- private $ignoredErrorsOnPackageAndPath = [];
+ private $ignoredErrorsOnDependencyAndPath = [];
/**
* @var list
@@ -94,6 +99,17 @@ class Configuration
*/
private $ignoredUnknownFunctionsRegexes = [];
+ /**
+ * Disable analysis of ext-* dependencies
+ *
+ * @return $this
+ */
+ public function disableExtensionsAnalysis(): self
+ {
+ $this->extensionsAnalysis = false;
+ return $this;
+ }
+
/**
* @return $this
*/
@@ -103,6 +119,9 @@ public function disableComposerAutoloadPathScan(): self
return $this;
}
+ /**
+ * @return $this
+ */
public function disableReportingUnmatchedIgnores(): self
{
$this->reportUnmatchedIgnores = false;
@@ -277,13 +296,34 @@ public function ignoreErrorsOnPaths(array $paths, array $errorTypes): self
public function ignoreErrorsOnPackage(string $packageName, array $errorTypes): self
{
$this->checkPackageName($packageName);
- $this->checkAllowedErrorTypeForPackageIgnore($errorTypes);
+ $this->ignoreErrorsOnDependency($packageName, $errorTypes);
+ return $this;
+ }
- $previousErrorTypes = $this->ignoredErrorsOnPackage[$packageName] ?? [];
- $this->ignoredErrorsOnPackage[$packageName] = array_merge($previousErrorTypes, $errorTypes);
+ /**
+ * @param list $errorTypes
+ * @return $this
+ * @throws InvalidConfigException
+ */
+ public function ignoreErrorsOnExtension(string $extension, array $errorTypes): self
+ {
+ $this->checkExtensionName($extension);
+ $this->ignoreErrorsOnDependency($extension, $errorTypes);
return $this;
}
+ /**
+ * @param list $errorTypes
+ * @throws InvalidConfigException
+ */
+ private function ignoreErrorsOnDependency(string $dependency, array $errorTypes): void
+ {
+ $this->checkAllowedErrorTypeForPackageIgnore($errorTypes);
+
+ $previousErrorTypes = $this->ignoredErrorsOnDependency[$dependency] ?? [];
+ $this->ignoredErrorsOnDependency[$dependency] = array_merge($previousErrorTypes, $errorTypes);
+ }
+
/**
* @param list $packageNames
* @param list $errorTypes
@@ -299,6 +339,21 @@ public function ignoreErrorsOnPackages(array $packageNames, array $errorTypes):
return $this;
}
+ /**
+ * @param list $extensions
+ * @param list $errorTypes
+ * @return $this
+ * @throws InvalidConfigException
+ */
+ public function ignoreErrorsOnExtensions(array $extensions, array $errorTypes): self
+ {
+ foreach ($extensions as $extension) {
+ $this->ignoreErrorsOnExtension($extension, $errorTypes);
+ }
+
+ return $this;
+ }
+
/**
* @param list $errorTypes
* @return $this
@@ -308,14 +363,37 @@ public function ignoreErrorsOnPackages(array $packageNames, array $errorTypes):
public function ignoreErrorsOnPackageAndPath(string $packageName, string $path, array $errorTypes): self
{
$this->checkPackageName($packageName);
+ $this->ignoreErrorsOnDependencyAndPath($packageName, $path, $errorTypes);
+ return $this;
+ }
+
+ /**
+ * @param list $errorTypes
+ * @return $this
+ * @throws InvalidPathException
+ * @throws InvalidConfigException
+ */
+ public function ignoreErrorsOnExtensionAndPath(string $extension, string $path, array $errorTypes): self
+ {
+ $this->checkExtensionName($extension);
+ $this->ignoreErrorsOnDependencyAndPath($extension, $path, $errorTypes);
+ return $this;
+ }
+
+ /**
+ * @param list $errorTypes
+ * @throws InvalidPathException
+ * @throws InvalidConfigException
+ */
+ private function ignoreErrorsOnDependencyAndPath(string $dependency, string $path, array $errorTypes): void
+ {
$this->checkAllowedErrorTypeForPathIgnore($errorTypes);
$this->checkAllowedErrorTypeForPackageIgnore($errorTypes);
$realpath = Path::realpath($path);
- $previousErrorTypes = $this->ignoredErrorsOnPackageAndPath[$packageName][$realpath] ?? [];
- $this->ignoredErrorsOnPackageAndPath[$packageName][$realpath] = array_merge($previousErrorTypes, $errorTypes);
- return $this;
+ $previousErrorTypes = $this->ignoredErrorsOnDependencyAndPath[$dependency][$realpath] ?? [];
+ $this->ignoredErrorsOnDependencyAndPath[$dependency][$realpath] = array_merge($previousErrorTypes, $errorTypes);
}
/**
@@ -334,6 +412,22 @@ public function ignoreErrorsOnPackageAndPaths(string $packageName, array $paths,
return $this;
}
+ /**
+ * @param list $paths
+ * @param list $errorTypes
+ * @return $this
+ * @throws InvalidPathException
+ * @throws InvalidConfigException
+ */
+ public function ignoreErrorsOnExtensionAndPaths(string $extension, array $paths, array $errorTypes): self
+ {
+ foreach ($paths as $path) {
+ $this->ignoreErrorsOnExtensionAndPath($extension, $path, $errorTypes);
+ }
+
+ return $this;
+ }
+
/**
* @param list $packages
* @param list $paths
@@ -351,6 +445,23 @@ public function ignoreErrorsOnPackagesAndPaths(array $packages, array $paths, ar
return $this;
}
+ /**
+ * @param list $extensions
+ * @param list $paths
+ * @param list $errorTypes
+ * @return $this
+ * @throws InvalidPathException
+ * @throws InvalidConfigException
+ */
+ public function ignoreErrorsOnExtensionsAndPaths(array $extensions, array $paths, array $errorTypes): self
+ {
+ foreach ($extensions as $extension) {
+ $this->ignoreErrorsOnExtensionAndPaths($extension, $paths, $errorTypes);
+ }
+
+ return $this;
+ }
+
/**
* @param list $classNames
* @return $this
@@ -406,8 +517,8 @@ public function getIgnoreList(): IgnoreList
return new IgnoreList(
$this->ignoredErrors,
$this->ignoredErrorsOnPath,
- $this->ignoredErrorsOnPackage,
- $this->ignoredErrorsOnPackageAndPath,
+ $this->ignoredErrorsOnDependency,
+ $this->ignoredErrorsOnDependencyAndPath,
$this->ignoredUnknownClasses,
$this->ignoredUnknownClassesRegexes,
$this->ignoredUnknownFunctions,
@@ -439,6 +550,11 @@ public function getPathsToScan(): array
return $this->pathsToScan;
}
+ public function shouldAnalyseExtensions(): bool
+ {
+ return $this->extensionsAnalysis;
+ }
+
public function shouldScanComposerAutoloadPaths(): bool
{
return $this->scanComposerAutoloadPaths;
@@ -476,6 +592,16 @@ private function isFilepathWithinPath(string $filePath, string $path): bool
return strpos($filePath, $path) === 0;
}
+ /**
+ * @throws InvalidConfigException
+ */
+ private function checkExtensionName(string $extension): void
+ {
+ if (strpos($extension, 'ext-') !== 0) {
+ throw new InvalidConfigException("Invalid php extension dependency name '$extension', it is expected to start with ext-");
+ }
+ }
+
/**
* @throws InvalidConfigException
*/
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Ignore/IgnoreList.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Ignore/IgnoreList.php
index 59da5a544..92e3e8ac2 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Ignore/IgnoreList.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Config/Ignore/IgnoreList.php
@@ -25,12 +25,12 @@ class IgnoreList
/**
* @var array>
*/
- private $ignoredErrorsOnPackage = [];
+ private $ignoredErrorsOnDependency = [];
/**
* @var array>>
*/
- private $ignoredErrorsOnPackageAndPath = [];
+ private $ignoredErrorsOnDependencyAndPath = [];
/**
* @var array
@@ -55,8 +55,8 @@ class IgnoreList
/**
* @param list $ignoredErrors
* @param array> $ignoredErrorsOnPath
- * @param array> $ignoredErrorsOnPackage
- * @param array>> $ignoredErrorsOnPackageAndPath
+ * @param array> $ignoredErrorsOnDependency
+ * @param array>> $ignoredErrorsOnDependencyAndPath
* @param list $ignoredUnknownClasses
* @param list $ignoredUnknownClassesRegexes
* @param list $ignoredUnknownFunctions
@@ -65,8 +65,8 @@ class IgnoreList
public function __construct(
array $ignoredErrors,
array $ignoredErrorsOnPath,
- array $ignoredErrorsOnPackage,
- array $ignoredErrorsOnPackageAndPath,
+ array $ignoredErrorsOnDependency,
+ array $ignoredErrorsOnDependencyAndPath,
array $ignoredUnknownClasses,
array $ignoredUnknownClassesRegexes,
array $ignoredUnknownFunctions,
@@ -79,13 +79,13 @@ public function __construct(
$this->ignoredErrorsOnPath[$path] = array_fill_keys($errorTypes, false);
}
- foreach ($ignoredErrorsOnPackage as $packageName => $errorTypes) {
- $this->ignoredErrorsOnPackage[$packageName] = array_fill_keys($errorTypes, false);
+ foreach ($ignoredErrorsOnDependency as $dependency => $errorTypes) {
+ $this->ignoredErrorsOnDependency[$dependency] = array_fill_keys($errorTypes, false);
}
- foreach ($ignoredErrorsOnPackageAndPath as $packageName => $paths) {
+ foreach ($ignoredErrorsOnDependencyAndPath as $dependency => $paths) {
foreach ($paths as $path => $errorTypes) {
- $this->ignoredErrorsOnPackageAndPath[$packageName][$path] = array_fill_keys($errorTypes, false);
+ $this->ignoredErrorsOnDependencyAndPath[$dependency][$path] = array_fill_keys($errorTypes, false);
}
}
@@ -116,7 +116,7 @@ public function getUnusedIgnores(): array
}
}
- foreach ($this->ignoredErrorsOnPackage as $packageName => $errorTypes) {
+ foreach ($this->ignoredErrorsOnDependency as $packageName => $errorTypes) {
foreach ($errorTypes as $errorType => $ignored) {
if (!$ignored) {
$unused[] = new UnusedErrorIgnore($errorType, null, $packageName);
@@ -124,7 +124,7 @@ public function getUnusedIgnores(): array
}
}
- foreach ($this->ignoredErrorsOnPackageAndPath as $packageName => $paths) {
+ foreach ($this->ignoredErrorsOnDependencyAndPath as $packageName => $paths) {
foreach ($paths as $path => $errorTypes) {
foreach ($errorTypes as $errorType => $ignored) {
if (!$ignored) {
@@ -240,12 +240,12 @@ private function shouldIgnoreUnknownFunctionByRegex(string $function): bool
/**
* @param ErrorType::SHADOW_DEPENDENCY|ErrorType::UNUSED_DEPENDENCY|ErrorType::DEV_DEPENDENCY_IN_PROD|ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV $errorType
*/
- public function shouldIgnoreError(string $errorType, ?string $realPath, ?string $packageName): bool
+ public function shouldIgnoreError(string $errorType, ?string $realPath, ?string $dependency): bool
{
$ignoredGlobally = $this->shouldIgnoreErrorGlobally($errorType);
$ignoredByPath = $realPath !== null && $this->shouldIgnoreErrorOnPath($errorType, $realPath);
- $ignoredByPackage = $packageName !== null && $this->shouldIgnoreErrorOnPackage($errorType, $packageName);
- $ignoredByPackageAndPath = $realPath !== null && $packageName !== null && $this->shouldIgnoreErrorOnPackageAndPath($errorType, $packageName, $realPath);
+ $ignoredByPackage = $dependency !== null && $this->shouldIgnoreErrorOnDependency($errorType, $dependency);
+ $ignoredByPackageAndPath = $realPath !== null && $dependency !== null && $this->shouldIgnoreErrorOnDependencyAndPath($errorType, $dependency, $realPath);
return $ignoredGlobally || $ignoredByPackageAndPath || $ignoredByPath || $ignoredByPackage;
}
@@ -281,10 +281,10 @@ private function shouldIgnoreErrorOnPath(string $errorType, string $filePath): b
/**
* @param ErrorType::* $errorType
*/
- private function shouldIgnoreErrorOnPackage(string $errorType, string $packageName): bool
+ private function shouldIgnoreErrorOnDependency(string $errorType, string $dependency): bool
{
- if (isset($this->ignoredErrorsOnPackage[$packageName][$errorType])) {
- $this->ignoredErrorsOnPackage[$packageName][$errorType] = true;
+ if (isset($this->ignoredErrorsOnDependency[$dependency][$errorType])) {
+ $this->ignoredErrorsOnDependency[$dependency][$errorType] = true;
return true;
}
@@ -294,12 +294,12 @@ private function shouldIgnoreErrorOnPackage(string $errorType, string $packageNa
/**
* @param ErrorType::* $errorType
*/
- private function shouldIgnoreErrorOnPackageAndPath(string $errorType, string $packageName, string $filePath): bool
+ private function shouldIgnoreErrorOnDependencyAndPath(string $errorType, string $packageName, string $filePath): bool
{
- if (isset($this->ignoredErrorsOnPackageAndPath[$packageName])) {
- foreach ($this->ignoredErrorsOnPackageAndPath[$packageName] as $path => $errorTypes) {
+ if (isset($this->ignoredErrorsOnDependencyAndPath[$packageName])) {
+ foreach ($this->ignoredErrorsOnDependencyAndPath[$packageName] as $path => $errorTypes) {
if ($this->isFilepathWithinPath($filePath, $path) && isset($errorTypes[$errorType])) {
- $this->ignoredErrorsOnPackageAndPath[$packageName][$path][$errorType] = true;
+ $this->ignoredErrorsOnDependencyAndPath[$packageName][$path][$errorType] = true;
return true;
}
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Initializer.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Initializer.php
index 8379b86f9..3c3e36c19 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Initializer.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Initializer.php
@@ -52,6 +52,8 @@ class Initializer
--ignore-shadow-deps Ignore all shadow dependency issues
--ignore-dev-in-prod-deps Ignore all dev dependency in production code issues
--ignore-prod-only-in-dev-deps Ignore all prod dependency used only in dev paths issues
+
+ --disable-ext-analysis Disable analysis of php extensions (e.g. ext-xml)
EOD;
/**
@@ -116,6 +118,7 @@ public function initConfiguration(
$config = new Configuration();
}
+ $disableExtAnalysis = $options->disableExtAnalysis === true;
$ignoreUnknownClasses = $options->ignoreUnknownClasses === true;
$ignoreUnknownFunctions = $options->ignoreUnknownFunctions === true;
$ignoreUnused = $options->ignoreUnusedDeps === true;
@@ -123,6 +126,10 @@ public function initConfiguration(
$ignoreDevInProd = $options->ignoreDevInProdDeps === true;
$ignoreProdOnlyInDev = $options->ignoreProdOnlyInDevDeps === true;
+ if ($disableExtAnalysis) {
+ $config->disableExtensionsAnalysis();
+ }
+
if ($ignoreUnknownClasses) {
$config->ignoreErrors([ErrorType::UNKNOWN_CLASS]);
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/Printer.php b/app/vendor/shipmonk/composer-dependency-analyser/src/Printer.php
index dc6684272..1bb9211ec 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/Printer.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/Printer.php
@@ -28,12 +28,18 @@ class Printer
*/
private $resource;
+ /**
+ * @var bool
+ */
+ private $noColor;
+
/**
* @param resource $resource
*/
- public function __construct($resource)
+ public function __construct($resource, bool $noColor)
{
$this->resource = $resource;
+ $this->noColor = $noColor;
}
public function printLine(string $string): void
@@ -52,7 +58,11 @@ public function print(string $string): void
private function colorize(string $string): string
{
- return str_replace(array_keys(self::COLORS), array_values(self::COLORS), $string);
+ return str_replace(
+ array_keys(self::COLORS),
+ $this->noColor ? '' : array_values(self::COLORS),
+ $string
+ );
}
}
diff --git a/app/vendor/shipmonk/composer-dependency-analyser/src/UsedSymbolExtractor.php b/app/vendor/shipmonk/composer-dependency-analyser/src/UsedSymbolExtractor.php
index 8f386c85c..c2a5c54f4 100644
--- a/app/vendor/shipmonk/composer-dependency-analyser/src/UsedSymbolExtractor.php
+++ b/app/vendor/shipmonk/composer-dependency-analyser/src/UsedSymbolExtractor.php
@@ -8,6 +8,7 @@
use function ltrim;
use function strlen;
use function strpos;
+use function strtolower;
use function substr;
use function token_get_all;
use const PHP_VERSION_ID;
@@ -19,14 +20,18 @@
use const T_CURLY_OPEN;
use const T_DOC_COMMENT;
use const T_DOLLAR_OPEN_CURLY_BRACES;
+use const T_DOUBLE_COLON;
use const T_ENUM;
use const T_FUNCTION;
+use const T_INSTEADOF;
use const T_INTERFACE;
use const T_NAME_FULLY_QUALIFIED;
use const T_NAME_QUALIFIED;
use const T_NAMESPACE;
use const T_NEW;
use const T_NS_SEPARATOR;
+use const T_NULLSAFE_OBJECT_OPERATOR;
+use const T_OBJECT_OPERATOR;
use const T_STRING;
use const T_TRAIT;
use const T_USE;
@@ -62,10 +67,13 @@ public function __construct(string $code)
* It does not produce any local names in current namespace
* - this results in very limited functionality in files without namespace
*
+ * @param array $extensionSymbols
* @return array>>
* @license Inspired by https://github.com/doctrine/annotations/blob/2.0.0/lib/Doctrine/Common/Annotations/TokenParser.php
*/
- public function parseUsedSymbols(): array
+ public function parseUsedSymbols(
+ array $extensionSymbols
+ ): array
{
$usedSymbols = [];
$useStatements = [];
@@ -107,13 +115,16 @@ public function parseUsedSymbols(): array
break;
case PHP_VERSION_ID >= 80000 ? T_NAMESPACE : -1:
+ // namespace change
$inGlobalScope = false;
- $useStatements = []; // reset use statements on namespace change
+ $useStatements = [];
+ $useStatementKinds = [];
break;
case PHP_VERSION_ID >= 80000 ? T_NAME_FULLY_QUALIFIED : -1:
$symbolName = $this->normalizeBackslash($token[1]);
- $kind = $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
+ $lowerSymbolName = strtolower($symbolName);
+ $kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
$usedSymbols[$kind][$symbolName][] = $token[2];
break;
@@ -122,24 +133,42 @@ public function parseUsedSymbols(): array
if (isset($useStatements[$neededAlias])) {
$symbolName = $useStatements[$neededAlias] . substr($token[1], strlen($neededAlias));
- $kind = $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
- $usedSymbols[$kind][$symbolName][] = $token[2];
-
} elseif ($inGlobalScope) {
$symbolName = $token[1];
- $kind = $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
- $usedSymbols[$kind][$symbolName][] = $token[2];
+ } else {
+ break;
}
+ $lowerSymbolName = strtolower($symbolName);
+ $kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null);
+ $usedSymbols[$kind][$symbolName][] = $token[2];
+
break;
case PHP_VERSION_ID >= 80000 ? T_STRING : -1:
$name = $token[1];
+ $lowerName = strtolower($name);
+ $pointerBeforeName = $this->pointer - 2;
+ $pointerAfterName = $this->pointer;
+
+ if (!$this->canBeSymbolName($pointerBeforeName, $pointerAfterName)) {
+ break;
+ }
if (isset($useStatements[$name])) {
$symbolName = $useStatements[$name];
$kind = $useStatementKinds[$name];
$usedSymbols[$kind][$symbolName][] = $token[2];
+
+ } elseif (isset($extensionSymbols[$lowerName])) {
+ $symbolName = $name;
+ $kind = $extensionSymbols[$lowerName];
+
+ if (!$inGlobalScope && $kind === SymbolKind::CLASSLIKE) {
+ break; // cannot use class-like symbols in non-global scope when not imported
+ }
+
+ $usedSymbols[$kind][$symbolName][] = $token[2];
}
break;
@@ -149,8 +178,10 @@ public function parseUsedSymbols(): array
$nextName = $this->parseNameForOldPhp();
if (substr($nextName, 0, 1) !== '\\') { // not a namespace-relative name, but a new namespace declaration
- $useStatements = []; // reset use statements on namespace change
+ // namespace change
$inGlobalScope = false;
+ $useStatements = [];
+ $useStatementKinds = [];
}
break;
@@ -158,9 +189,10 @@ public function parseUsedSymbols(): array
case PHP_VERSION_ID < 80000 ? T_NS_SEPARATOR : -1:
$pointerBeforeName = $this->pointer - 2;
$symbolName = $this->normalizeBackslash($this->parseNameForOldPhp());
+ $lowerSymbolName = strtolower($symbolName);
if ($symbolName !== '') { // e.g. \array (NS separator followed by not-a-name)
- $kind = $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
+ $kind = $extensionSymbols[$lowerSymbolName] ?? $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
$usedSymbols[$kind][$symbolName][] = $token[2];
}
@@ -169,23 +201,39 @@ public function parseUsedSymbols(): array
case PHP_VERSION_ID < 80000 ? T_STRING : -1:
$pointerBeforeName = $this->pointer - 2;
$name = $this->parseNameForOldPhp();
+ $lowerName = strtolower($name);
+ $pointerAfterName = $this->pointer - 1;
+
+ if (!$this->canBeSymbolName($pointerBeforeName, $pointerAfterName)) {
+ break;
+ }
if (isset($useStatements[$name])) { // unqualified name
$symbolName = $useStatements[$name];
$kind = $useStatementKinds[$name];
$usedSymbols[$kind][$symbolName][] = $token[2];
+ } elseif (isset($extensionSymbols[$lowerName])) {
+ $symbolName = $name;
+ $kind = $extensionSymbols[$lowerName];
+
+ if (!$inGlobalScope && $kind === SymbolKind::CLASSLIKE) {
+ break; // cannot use class-like symbols in non-global scope when not imported
+ }
+
+ $usedSymbols[$kind][$symbolName][] = $token[2];
+
} else {
[$neededAlias] = explode('\\', $name, 2);
if (isset($useStatements[$neededAlias])) { // qualified name
$symbolName = $useStatements[$neededAlias] . substr($name, strlen($neededAlias));
- $kind = $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
+ $kind = $this->getFqnSymbolKind($pointerBeforeName, $pointerAfterName, false);
$usedSymbols[$kind][$symbolName][] = $token[2];
} elseif ($inGlobalScope && strpos($name, '\\') !== false) {
$symbolName = $name;
- $kind = $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false);
+ $kind = $this->getFqnSymbolKind($pointerBeforeName, $pointerAfterName, false);
$usedSymbols[$kind][$symbolName][] = $token[2];
}
}
@@ -216,7 +264,7 @@ public function parseUsedSymbols(): array
}
}
- return $usedSymbols; // @phpstan-ignore-line Not enough precise analysis "Offset 'kind' (1|2|3) does not accept type int<1, max>"
+ return $usedSymbols;
}
/**
@@ -346,44 +394,89 @@ private function getFqnSymbolKind(
return SymbolKind::CLASSLIKE;
}
+ $tokenBeforeName = $this->getTokenBefore($pointerBeforeName);
+ $tokenAfterName = $this->getTokenAfter($pointerAfterName);
+
+ if (
+ $tokenAfterName === '('
+ && $tokenBeforeName[0] !== T_NEW // eliminate new \ClassName(
+ ) {
+ return SymbolKind::FUNCTION;
+ }
+
+ return SymbolKind::CLASSLIKE; // constant may fall here, this is eliminated later
+ }
+
+ private function canBeSymbolName(
+ int $pointerBeforeName,
+ int $pointerAfterName
+ ): bool
+ {
+ $tokenBeforeName = $this->getTokenBefore($pointerBeforeName);
+ $tokenAfterName = $this->getTokenAfter($pointerAfterName);
+
+ if (
+ $tokenBeforeName[0] === T_DOUBLE_COLON
+ || $tokenBeforeName[0] === T_INSTEADOF
+ || $tokenBeforeName[0] === T_AS
+ || $tokenBeforeName[0] === T_FUNCTION
+ || $tokenBeforeName[0] === T_OBJECT_OPERATOR
+ || $tokenBeforeName[0] === T_NAMESPACE
+ || $tokenBeforeName[0] === (PHP_VERSION_ID > 80000 ? T_NULLSAFE_OBJECT_OPERATOR : -1)
+ || $tokenAfterName[0] === T_INSTEADOF
+ || $tokenAfterName[0] === T_AS
+ || $tokenAfterName === ':'
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return array{int, string}|string
+ */
+ private function getTokenBefore(int $pointer)
+ {
do {
- $tokenBeforeName = $this->tokens[$pointerBeforeName];
+ $token = $this->tokens[$pointer];
- if (!is_array($tokenBeforeName)) {
+ if (!is_array($token)) {
break;
}
- if ($tokenBeforeName[0] === T_WHITESPACE || $tokenBeforeName[0] === T_COMMENT || $tokenBeforeName[0] === T_DOC_COMMENT) {
- $pointerBeforeName--;
+ if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_DOC_COMMENT) {
+ $pointer--;
continue;
}
break;
- } while ($pointerBeforeName >= 0);
+ } while ($pointer >= 0);
+
+ return $token;
+ }
+ /**
+ * @return array{int, string}|string
+ */
+ private function getTokenAfter(int $pointer)
+ {
do {
- $tokenAfterName = $this->tokens[$pointerAfterName];
+ $token = $this->tokens[$pointer];
- if (!is_array($tokenAfterName)) {
+ if (!is_array($token)) {
break;
}
- if ($tokenAfterName[0] === T_WHITESPACE || $tokenAfterName[0] === T_COMMENT || $tokenAfterName[0] === T_DOC_COMMENT) {
- $pointerAfterName++;
+ if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_DOC_COMMENT) {
+ $pointer++;
continue;
}
break;
- } while ($pointerAfterName < $this->numTokens);
-
- if (
- $tokenAfterName === '('
- && $tokenBeforeName[0] !== T_NEW // eliminate new \ClassName(
- ) {
- return SymbolKind::FUNCTION;
- }
+ } while ($pointer < $this->numTokens);
- return SymbolKind::CLASSLIKE; // constant may fall here, this is eliminated later
+ return $token;
}
}